एक NumPy सरणी का इन-प्लेस प्रकार रूपांतरण


127

के एक NumPy सरणी को देखते हुए int32, मैं इसे float32 जगह में कैसे परिवर्तित करूं ? इसलिए मूल रूप से, मैं करना चाहूंगा

a = a.astype(numpy.float32)

सरणी की नकल के बिना। यह बड़ा है।

ऐसा करने का कारण यह है कि मेरे पास गणना के लिए दो एल्गोरिदम हैं a। उनमें से एक एक सरणी देता है int32, दूसरा एक सरणी देता है float32(और यह दो अलग-अलग एल्गोरिदम में अंतर्निहित है)। सभी आगे की गणना यह मानती है कि aयह एक सरणी है float32

वर्तमान में मैं एक सी फ़ंक्शन में रूपांतरण को कॉल करता हूं ctypes। क्या पायथन में ऐसा करने का कोई तरीका है?


का उपयोग कर ctypesके रूप में ज्यादा "पायथन में" है numpy। :)
कार्ल केनचेल

3
@ कार्ल: नहीं, क्योंकि मुझे सी फंक्शन को कोड करना और संकलित करना है।
स्वेन मार्नाच

ओह मैं समझा। मुझे लगता है कि आप शायद इस पर एसओएल हैं।
कार्ल केनचेल

3
@ और: यह बताने के कई तरीके हैं कि क्या यह एक कॉपी लौटाता है। उनमें से एक प्रलेखन पढ़ना है ।
स्वेन मार्नाच

1
इन-प्लेस का अर्थ है "मूल सरणी के समान मेमोरी का उपयोग करना"। स्वीकृत उत्तर पर एक नज़र डालें - अंतिम भाग से पता चलता है कि नए मूल्यों ने वास्तव में एक ही स्मृति को अधिलेखित कर दिया है।
स्वेन मार्नाच

जवाबों:


110

आप एक अलग dtype के साथ एक दृश्य बना सकते हैं, और फिर दृश्य में इन-प्लेस कॉपी कर सकते हैं:

import numpy as np
x = np.arange(10, dtype='int32')
y = x.view('float32')
y[:] = x

print(y)

पैदावार

array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9.], dtype=float32)

रूपांतरण दिखाने के लिए था यथा-स्थान, ध्यान दें कि कॉपी करने से x करने के लिए yबदल x:

print(x)

प्रिंट

array([         0, 1065353216, 1073741824, 1077936128, 1082130432,
       1084227584, 1086324736, 1088421888, 1090519040, 1091567616])

26
उन लोगों के लिए नोट (मेरे जैसे) जो अलग-अलग बाइट-आकार के dtype (जैसे 32 से 16 बिट्स) के बीच रूपांतरण चाहते हैं: यह विधि विफल हो जाती है क्योंकि y.size <> x.size। तार्किक एक बार जब आप इसके बारे में सोचते हैं :-(
जुह_

क्या यह समाधान Numpy के कुछ पुराने संस्करण के लिए काम कर रहा था? जब मैं np.arange(10, dtype=np.int32).view(np.float32)Numpy 1.8.2 पर करता हूं , मुझे मिलता है array([ 0.00000000e+00, 1.40129846e-45, ... [snip] ... 1.26116862e-44], dtype=float32)
बास स्विंकल्स

3
@BasSwinckels: यह अपेक्षित है। रूपांतरण तब होता है जब आप असाइन करते हैं y[:] = x
अनटुब

मूल उत्तर और @Ju__ द्वारा संदर्भित आइटम (बिट्स की संख्या) के बारे में किए गए बिंदु को स्पष्ट करने के लिए जैसे: a = np.arange(10, dtype='float32'); b = a[::-1]; c = np.vstack((a,b)); d = c.view('float64')यह कोड 10 + 10 फ्लोट 32 लेता है और 10 में परिणाम देता है, बजाय 20 फ्लोट64
डेकेनेल 10

1
यह स्थान परिवर्तन स्मृति उपयोग पर सहेज सकता है, लेकिन यह एक साधारण x.astype(float)रूपांतरण की तुलना में धीमा है । जब तक आपकी स्क्रिप्ट MemoryError पर सीमाबद्ध नहीं होती, मैं इसकी अनुशंसा नहीं करूंगा।
हंपुलज

158

अद्यतन: यह फ़ंक्शन केवल कॉपी से बचता है यदि यह हो सकता है, इसलिए यह इस प्रश्न का सही उत्तर नहीं है। unutbu का जवाब सही है।


a = a.astype(numpy.float32, copy=False)

numpy astype में एक कॉपी फ़्लैग है। हमें इसका उपयोग क्यों नहीं करना चाहिए?


14
एक बार जब यह पैरामीटर एक न्यूपे रिलीज में समर्थित होता है, तो हम निश्चित रूप से इसका उपयोग कर सकते हैं, लेकिन वर्तमान में यह केवल विकास शाखा में उपलब्ध है। और जिस समय मैंने यह प्रश्न पूछा, यह बिल्कुल भी मौजूद नहीं था।
स्वेन मार्नाच

2
@SvenMarnach यह अब समर्थित है, कम से कम मेरे संस्करण (1.7.1) में।
PhilMacKay 20

यह नवीनतम संख्यात्मक संस्करण के साथ python3.3 में पूरी तरह से काम करता है।
सीएचएम

1
मुझे यह लगभग a = aview ((फ़्लोट, लेन (a.dtype.names)) की तुलना में 700x धीमा लगता है)
JJ

14
कॉपी फ़्लैग केवल यह कहता है कि यदि बदलाव कॉपी के बिना किया जा सकता है, तो यह कॉपी के बिना किया जाएगा। हालांकि यह अलग प्रकार है यह अभी भी हमेशा कॉपी होगा।
कोडरफ़ॉर्फ़िनिटी

14

आप इस तरह परिवर्तित किए बिना सरणी प्रकार बदल सकते हैं:

a.dtype = numpy.float32

लेकिन पहले आपको सभी पूर्णांकों को किसी ऐसी चीज़ में बदलना होगा, जिसकी व्याख्या इसी फ़्लोट के रूप में की जाएगी। ऐसा करने का एक बहुत धीमा तरीका इस तरह से अजगर के structमॉड्यूल का उपयोग करना होगा :

def toi(i):
    return struct.unpack('i',struct.pack('f',float(i)))[0]

... आपके सरणी के प्रत्येक सदस्य पर लागू होता है।

लेकिन शायद एक तेज़ तरीका यह होगा कि मैं खसखस ​​के ctypeslib टूल का उपयोग करूं (जो कि मैं अपरिचित हूं)

- संपादित करें -

चूंकि ctypeslib doesn't काम करने लगता है, तो मैं विशिष्ट numpy.astypeविधि के साथ रूपांतरण के साथ आगे बढ़ूंगा , लेकिन ब्लॉक आकारों में आगे बढ़ें जो आपकी मेमोरी सीमा के भीतर हैं:

a[0:10000] = a[0:10000].astype('float32').view('int32')

... तो जब किया dtype बदलें।

यहां एक फ़ंक्शन है जो किसी भी संगत dtypes के लिए कार्य को पूरा करता है (केवल समान आकार वाले dtypes के लिए काम करता है) और ब्लॉक-आकार पर उपयोगकर्ता-नियंत्रण के साथ मनमाने ढंग से आकार के सरणियों को संभालता है:

import numpy

def astype_inplace(a, dtype, blocksize=10000):
    oldtype = a.dtype
    newtype = numpy.dtype(dtype)
    assert oldtype.itemsize is newtype.itemsize
    for idx in xrange(0, a.size, blocksize):
        a.flat[idx:idx + blocksize] = \
            a.flat[idx:idx + blocksize].astype(newtype).view(oldtype)
    a.dtype = newtype

a = numpy.random.randint(100,size=100).reshape((10,10))
print a
astype_inplace(a, 'float32')
print a

1
आपके उत्तर के लिए धन्यवाद। ईमानदारी से, मुझे नहीं लगता कि यह बड़े सरणियों के लिए बहुत उपयोगी है - यह बहुत धीमा है। एक अलग प्रकार के रूप में सरणी के डेटा को फिर से लिखना आसान है - उदाहरण के लिए कॉल करके a.view(numpy.float32)। कठिन हिस्सा वास्तव में डेटा परिवर्तित कर रहा है। numpy.ctypeslibकेवल डेटा को फिर से परिभाषित करने में मदद करता है, वास्तव में इसे परिवर्तित करने के साथ नहीं।
स्वेन मार्नाच

ठीक है। मुझे यकीन नहीं था कि आपकी मेमोरी / प्रोसेसर की सीमाएं क्या थीं। मेरा संपादन देखें।
पॉल 16

अद्यतन के लिए धन्यवाद। इसे अवरुद्ध करना एक अच्छा विचार है - शायद सबसे अच्छा आप वर्तमान NumPy इंटरफ़ेस के साथ प्राप्त कर सकते हैं। लेकिन इस मामले में, मैं शायद अपने वर्तमान ctypes समाधान से चिपके रहूंगा।
स्वेन मार्नाच

-1
import numpy as np
arr_float = np.arange(10, dtype=np.float32)
arr_int = arr_float.view(np.float32)

सरणी में स्थान बदलने के लिए दृश्य () और पैरामीटर 'dtype' का उपयोग करें।


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

आपका मतलब क्या है? dtype सिर्फ मेमोरी में डेटा की उपस्थिति है, यह वास्तव में काम करता है। कभी-कभी np.astype में, पैरामीटर 'कास्टिंग' कन्वर्ट विधि डिफ़ॉल्ट 'असुरक्षित' को नियंत्रित कर सकता है।
蒋志强

हाँ, मैं पहले स्वीकार किए गए उत्तर से सहमत हूँ। हालाँकि arr_.astype (new_dtype, copy = False) अभी भी एक नया आवंटित सरणी देता है। कैसे संतुष्ट करने के लिए dtype, orderऔर subokआवश्यकताओं सरणी की एक प्रति वापस जाने के लिए? मैं इसे हल नहीं करता।
蒋志强

-5

इसे इस्तेमाल करो:

In [105]: a
Out[105]: 
array([[15, 30, 88, 31, 33],
       [53, 38, 54, 47, 56],
       [67,  2, 74, 10, 16],
       [86, 33, 15, 51, 32],
       [32, 47, 76, 15, 81]], dtype=int32)

In [106]: float32(a)
Out[106]: 
array([[ 15.,  30.,  88.,  31.,  33.],
       [ 53.,  38.,  54.,  47.,  56.],
       [ 67.,   2.,  74.,  10.,  16.],
       [ 86.,  33.,  15.,  51.,  32.],
       [ 32.,  47.,  76.,  15.,  81.]], dtype=float32)

5
क्या आप सुनिश्चित हैं कि प्रतिलिपि नहीं है? क्या आप इसे जांच सकते हैं और थोड़ा और समझा सकते हैं?
मिशेल डीमिको

-5

a = np.subtract(a, 0., dtype=np.float32)


1
हालांकि यह कोड स्निपेट समाधान हो सकता है, जिसमें स्पष्टीकरण भी शामिल है , जो आपके पोस्ट की गुणवत्ता को बेहतर बनाने में मदद करता है। याद रखें कि आप भविष्य में पाठकों के लिए प्रश्न का उत्तर दे रहे हैं, और उन लोगों को आपके कोड सुझाव के कारणों का पता नहीं चल सकता है।
सेबेस्टियलोनो

यह स्थान रूपांतरण में क्यों होना चाहिए ? numpy.subtractएक प्रति लौटा रहा है, है ना? केवल aएक और डेटा के लिए नाम का पुन: उपयोग किया गया ... कृपया समझाएं, अगर मैं इस बारे में गलत हूं।
कोफिन 20

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