मैं एक जनरेटर से एक संख्यात्मक सरणी कैसे बनाऊं?


166

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

मुझे समस्या के बारे में बताएं:

>>> 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])

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


6
यह एक दिलचस्प मुद्दा है। मैं इसके द्वारा आया था from numpy import *; print any(False for i in range(1))- जो बिल्ट-इन छाया देता है any()और विपरीत परिणाम उत्पन्न करता है (जैसा कि मैं अब जानता हूं)।
मूओइपिप

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

1
@ मोम मैं उसी खदान पर कदम रखा। जाहिरा तौर पर यह NumPy सूची (और पहले ) पर उठाया गया था , यह निष्कर्ष निकालता है कि अपवाद को बढ़ाने के लिए इसे नहीं बदला जाएगा और किसी को हमेशा नेमस्पेस का उपयोग करना चाहिए।
अलेई

जवाबों:


128

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

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

  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

1 शायद वही है जो आप ढूंढ रहे हैं। 2 अंतरिक्ष अक्षम है, और 3 समय अक्षम है (आपको दो बार जनरेटर से गुजरना होगा)।


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

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

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

2
खाली का उपयोग करना थोड़ा तेज है। चूंकि आप किसी भी तरह से मूल्यों को शुरू करने जा रहे हैं, इसलिए इसे दो बार करने की आवश्यकता नहीं है।
कौशिक घोष

नीचे भी देखें @ ढिल्लों का उत्तर जो तेजी से 1. से अधिक है
बिल

206

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

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


आप इसे प्रश्न पर कैसे लागू करेंगे? numpy.fromiter(gimme(), float, count=-1)काम नहीं करता। किसलिए somethingखड़ा है?
मथियास 009

1
@ Matthias009 numpy.fromiter(gimme(), float, count=-1)मेरे लिए काम करता है।
मूइओपिप

14
एक धागा जो समझाता है कि fromiterकेवल 1D सरणियों पर काम क्यों होता है: mail.scipy.org/pipermail/numpy-discussion/2007-August/…
अधिकतम

2
fwiw, count=-1को निर्दिष्ट करने की आवश्यकता नहीं है, क्योंकि यह डिफ़ॉल्ट है।
पूछवचन

5
यदि आप पहले से ही चलने योग्य की लंबाई जानते हैं, तो countप्रदर्शन में सुधार करने के लिए निर्दिष्ट करें । इस तरह यह मांग पर आकार देने के बजाय मूल्यों के साथ भरने से पहले मेमोरी को आवंटित करता है (देखें प्रलेखन numpy.fromiter)
एड़ी

15

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

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

यह 1D सरणियों के लिए भी काम करता है:

>>> 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]। कार्यान्वयन यहाँ पाया जा सकता है


1
यह एक साफ समाधान है, इंगित करने के लिए धन्यवाद। लेकिन यह प्रयोग करने की तुलना में थोड़ा धीमा (मेरे आवेदन में) प्रतीत होता है np.array(tuple(mygen))। यहां परीक्षा परिणाम हैं:%timeit np.stack(permutations(range(10), 7)) 1 loop, best of 3: 1.9 s per loop%timeit np.array(tuple(permutations(range(10), 7))) 1 loop, best of 3: 427 ms per loop
बिल

13
यह बहुत अच्छा लगता है और मेरे लिए काम करता है। लेकिन Numpy 1.16.1 के साथ मुझे यह चेतावनी मिली:FutureWarning: arrays to stack must be passed as a "sequence" type such as list or tuple. Support for non-sequence iterables such as generators is deprecated as of NumPy 1.16 and will raise an error in the future.
जोसेफ शेडी

6

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


0

Vstack , hstack , और dstack कार्यों इनपुट जनरेटर कि उपज बहुआयामी सरणियों के रूप में ले सकते हैं।


3
क्या आप लिंक बदलने या कुछ और करने के मामले में एक उदाहरण दे सकते हैं? :)
अरी कूपर-डेविस

ये फ़ंक्शन सरणियों का एक जनरेटर ले सकते हैं, मूल्यों का जनरेटर नहीं
रेटनिक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.