2008-12-15 26 views
112

मैं जनरेटर ऑब्जेक्ट से एक numpy सरणी कैसे बना सकता हूं?मैं जनरेटर से एक numpy सरणी कैसे बना सकता हूं?

मुझे समस्या को वर्णन करते हैं:

>>> import numpy 
>>> def gimme(): 
... for x in xrange(10): 
...  yield x 
... 
>>> gimme() 
<generator object at 0x28a1758> 
>>> list(gimme()) 
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
>>> numpy.array(xrange(10)) 
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 
>>> numpy.array(gimme()) 
array(<generator object at 0x28a1758>, dtype=object) 
>>> numpy.array(list(gimme())) 
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 

इस उदाहरण में, गिम्मी() जनरेटर जिसका उत्पादन मैं एक सरणी में बदलने के लिए चाहते हैं। हालांकि, सरणी कन्स्ट्रक्टर जनरेटर पर पुनरावृत्ति नहीं करता है, यह बस जनरेटर को ही स्टोर करता है। मेरा इच्छित व्यवहार यह है कि numpy.array (सूची (gimme()) से), लेकिन मैं एक ही समय में इंटरमीडिएट सूची और अंतिम सरणी को स्मृति में रखने के मेमोरी ओवरहेड का भुगतान नहीं करना चाहता हूं। क्या कोई और जगह-कुशल तरीका है?

+5

यह एक दिलचस्प मुद्दा है। मैं 'numpy आयात * से' इस पर आया; किसी भी प्रिंट करें (रेंज के लिए झूठी (1)) '- जो अंतर्निहित ['any()'] (http://docs.python.org/library/functions.html#any) छाया करता है और इसके विपरीत बनाता है नतीजा (जैसा कि अब मुझे पता है)। – moooeeeep

+4

@moooeeeep यह भयानक है। यदि जनरेटर के रूप में जेनरेटर का इलाज करने के लिए 'numpy' नहीं (या नहीं करना चाहता), कम से कम इसे एक अपवाद उठाया जाना चाहिए जब इसे जनरेटर को तर्क के रूप में प्राप्त किया जाए। – max

+1

@ मैक्स मैं सटीक उसी खान पर कदम रखा। जाहिर है यह [NumPy सूची पर] उठाया गया था (http://thread.gmane.org/gmane.comp.python.numeric.general/47681/focus=47702) (और [पहले] (http: //thread.gmane .org/gmane.comp.python.numeric.general/13197)) निष्कर्ष निकाला है कि यह अपवाद बढ़ाने के लिए नहीं बदला जाएगा और किसी को हमेशा नामस्थान का उपयोग करना चाहिए। – alexei

उत्तर

93

पागल सूची के विपरीत, अजीब सरणी को उनकी लंबाई को निर्माण समय पर स्पष्ट रूप से सेट करने की आवश्यकता होती है। यह आवश्यक है ताकि प्रत्येक आइटम के लिए स्थान स्मृति में आवंटित किया जा सके। अभिसरण आवंटन numpy arrays की मुख्य विशेषता है: यह देशी कोड कार्यान्वयन के साथ संयुक्त है नियमित संचालन से अधिक तेज़ी से निष्पादित करने पर।

इसे ध्यान में रखते हुए, यह एक जनरेटर वस्तु लेने के लिए और यह एक सरणी में बदलने के लिए तकनीकी रूप से असंभव है जब तक आप या तो:

  1. भविष्यवाणी कर सकते हैं जब चलाने के कितने तत्वों यह निकलेगा:

    my_array = numpy.empty(predict_length()) 
    for i, el in enumerate(gimme()): my_array[i] = el 
    
  2. एक मध्यवर्ती सूची में उसके तत्वों स्टोर करने के लिए तैयार हैं:

    my_array = numpy.array(list(gimme())) 
    
  3. दो समान जेनरेटर, कुल लंबाई को खोजने के लिए पहले एक के माध्यम से चलाने कर सकते हैं, सरणी को प्रारंभ करें, और फिर जनरेटर के माध्यम से चलाने फिर से प्रत्येक तत्व को खोजने के लिए:

    length = sum(1 for el in gimme()) 
    my_array = numpy.empty(length) 
    for i, el in enumerate(gimme()): my_array[i] = el 
    

शायद है आपको किसका इंतज़ार है। अंतरिक्ष अक्षम है, और समय अक्षम है (आपको जनरेटर को दो बार जाना होगा)।

+7

बिल्टिन 'array.array' एक संगत गैर-लिंक्ड सूची है, और आप बस' array.array ('f', जनरेटर) 'कर सकते हैं। कहने के लिए यह असंभव है भ्रामक है। यह सिर्फ गतिशील आवंटन है। – Cuadue

+0

क्यों numpy.array स्मृति आवंटन को बिल्टिन array.array जैसा नहीं करता है, जैसा कि क्यूड्यू कहते हैं। व्यापार क्या है? मैं पूछता हूं क्योंकि दोनों उदाहरणों में आवंटित आवंटित स्मृति है। या नहीं? – jgomo3

+2

numpy अपने सरणी आकार को बदलने के लिए मानता है। यह स्मृति के एक ही हिस्से के विभिन्न विचारों पर भारी निर्भर करता है, इसलिए सरणी को विस्तारित करने और पुन: आवंटित करने की अनुमति देने के लिए संकेतों को सक्षम करने के लिए संकेत की अतिरिक्त परत की आवश्यकता होगी, उदाहरण के लिए। – joeln

150

इस स्टैक ओवरफ्लो परिणाम के पीछे एक Google, मैंने पाया कि numpy.fromiter(data, dtype, count) है। डिफ़ॉल्ट count=-1 सभी तत्वों को पुन: प्रयोज्य से लेता है। इसे स्पष्ट रूप से सेट करने के लिए dtype की आवश्यकता है।मेरे मामले में, यह काम किया:

numpy.fromiter(something.generate(from_this_input), float)

+0

आप इस सवाल पर कैसे लागू होंगे? 'numpy.fromiter (gimme(), float, count = -1) 'काम नहीं करता है। 'कुछ' के लिए क्या खड़ा है? –

+0

something.generate सिर्फ जनरेटर –

+1

@ Matthias009 'numpy.fromiter (gimme(), float, count = -1) का नाम है, मेरे लिए काम करता है। – moooeeeep

5

कुछ हद तक स्पर्शरेखा, लेकिन अगर आपके जनरेटर एक सूची समझ है, तो आप numpy.where उपयोग कर सकते हैं और अधिक प्रभावी ढंग से अपने परिणाम प्राप्त करने के (मैं इस पोस्ट को देखने के बाद मेरे अपने कोड में यह पता चला)

3

आप numpy.fromiter() के साथ एक जनरेटर से एक 1 डी सरणी बना सकते हैं, आप numpy.stack के साथ एक जनरेटर से एक एन डी सरणी बना सकते हैं:

>>> mygen = (np.ones((5, 3)) for _ in range(10)) 
>>> x = numpy.stack(mygen) 
>>> x.shape 
(10, 5, 3) 

यह भी w -1 डी सरणियों के लिए orks:

>>> numpy.stack(2*i for i in range(10)) 
array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18]) 

ध्यान दें कि numpy.stack आंतरिक जनरेटर लगता है और arrays = [asanyarray(arr) for arr in arrays] साथ एक मध्यवर्ती सूची पैदा कर रही है। कार्यान्वयन here पाया जा सकता है।

+0

यह एक साफ समाधान है, जो इंगित करने के लिए धन्यवाद। लेकिन यह 'np.array (tuple (mygen)) का उपयोग करने से काफी धीमा (मेरे आवेदन में) लगता है। यहां परीक्षा परिणाम दिए गए हैं: '% टाइमिट एनपी.स्टैक (क्रमपरिवर्तन (सीमा (10), 7)) 1 लूप, 3% 1.9 एस प्रति लूप ''% timeit np.array की तुलना में (tuple (क्रमपरिवर्तन (रेंज (10), 7))) 1 लूप, 3: 427 एमएस प्रति लूप 'का सर्वश्रेष्ठ – Bill

संबंधित मुद्दे