2014-11-18 16 views
37

आकृति बदलें() फ़ंक्शन के बारे में numpy manual में, यह कहना हैसंगत और गैर-संगत सरणी के बीच क्या अंतर है?

>>> a = np.zeros((10, 2)) 
# A transpose make the array non-contiguous 
>>> b = a.T 
# Taking a view makes it possible to modify the shape without modifying the 
# initial object. 
>>> c = b.view() 
>>> c.shape = (20) 
AttributeError: incompatible shape for a non-contiguous array 

मेरे प्रश्न हैं:

  1. सतत और असन्निकट सरणियों क्या हैं? क्या यह सी में What is a contiguous memory block?
  2. में संगत स्मृति ब्लॉक के समान है क्या इन दोनों के बीच कोई प्रदर्शन अंतर है? हमें एक या दूसरे का उपयोग कब करना चाहिए?
  3. ट्रांसफर क्यों सरणी को गैर-संगत बनाता है?
  4. c.shape = (20)incompatible shape for a non-contiguous array त्रुटि क्यों फेंकता है?

आपके उत्तर के लिए धन्यवाद!

उत्तर

66

एक संगत सरणी केवल स्मृति की एक अखंड ब्लॉक में संग्रहीत एक सरणी है: सरणी में अगले मान तक पहुंचने के लिए, हम बस अगले मेमोरी पते पर जाते हैं।

2 डी सरणी arr = np.arange(12).reshape(3,4) पर विचार करें। यह इस तरह दिखता है:

enter image description here

कंप्यूटर की स्मृति में, arr के मूल्यों को इस तरह जमा हो जाती है:

enter image description here

इसका मतलब यह है arr एक सी सन्निहित क्योंकि सरणी है पंक्तियों स्मृति के संगत ब्लॉक के रूप में संग्रहीत हैं। अगली मेमोरी एड्रेस उस पंक्ति पर अगली पंक्ति मान रखती है। यदि हम एक कॉलम को नीचे ले जाना चाहते हैं, तो हमें केवल तीन ब्लॉक पर कूदने की आवश्यकता है (उदाहरण के लिए 0 से 4 तक कूदने का मतलब है कि हम 1,2 और 3 से अधिक छोड़ते हैं)।

arr.T के साथ सरणी को ट्रांसफर करना मतलब है कि सी contiguity खो गया है क्योंकि आसन्न पंक्ति प्रविष्टियां अब आसन्न स्मृति पते में नहीं हैं। हालांकि, arr.Tफोरट्रान सन्निहितकॉलम स्मृति से सटे ब्लॉक में हैं के बाद से है:

enter image description here


अभिनय की दृष्टि से, स्मृति पतों जो एक दूसरे के बगल में हैं तक पहुँचने बहुत बार से अधिक तेजी से है उन पते तक पहुंच जो अधिक "फैल गए" हैं (रैम से मूल्य प्राप्त करने से कई पड़ोसी पतों को सीपीयू के लिए लाया जा सकता है और कैश किया जा सकता है।) इसका मतलब है कि संगत सरणी पर संचालन अक्सर तेज हो जाएगा।

सी संगत मेमोरी लेआउट के परिणामस्वरूप, पंक्ति-वार ऑपरेशंस कॉलम-वार ऑपरेशंस की तुलना में आमतौर पर तेज़ होते हैं।उदाहरण के लिए, आप आमतौर पर पाएंगे कि

np.sum(arr, axis=1) # sum the rows 

की तुलना में थोड़ा तेज है:

np.sum(arr, axis=0) # sum the columns 

इसी तरह, स्तंभों पर कार्रवाई फोरट्रान सन्निहित सरणियों के लिए थोड़ा तेज किया जाएगा।


अंत में, हम एक नया आकार निर्दिष्ट करके फोरट्रान संगत सरणी को क्यों नहीं फहरा सकते?

>>> arr2 = arr.T 
>>> arr2.shape = 12 
AttributeError: incompatible shape for a non-contiguous array 
इस के लिए

आदेश में संभव NumPy इस तरह एक साथ arr.T की पंक्तियों डाल करने के लिए होता हो:

enter image description here

(स्थापना shape सीधे विशेषता सी आदेश मान लिया गया है - यानी NumPy की कोशिश करता है ऑपरेशन पंक्ति-वार प्रदर्शन करें।)

ऐसा करना असंभव है। किसी भी धुरी के लिए, सरणी के अगले तत्व पर जाने के लिए NumPy को स्थिर स्ट्रॉइड लम्बाई (बाइट्स की संख्या को स्थानांतरित करने की आवश्यकता है) की आवश्यकता होती है। इस तरह से arr.T को फ़्लैटन करने के लिए सरणी के लगातार मूल्यों को पुनर्प्राप्त करने के लिए स्मृति में आगे और पीछे छोड़ने की आवश्यकता होगी।

यदि हमने arr2.reshape(12) लिखा है, तो NumPy एआर 2 के मानों को स्मृति के नए ब्लॉक में कॉपी करेगा (क्योंकि यह इस आकार के मूल डेटा पर एक दृश्य नहीं लौटा सकता है)।

+0

मुझे लगता है कि यह एक नोट के साथ उपयोगी होगा कि किसी भी क्रम में कौन सी अनुक्रमणिका एक दूसरे के बगल में है: 'सी' के लिए अंतिम सूचकांक और' एफ' के लिए पहली अनुक्रमणिका, या एनडी सरणी के लिए .. बाद में इंडेक्स बंद हैं 'सी' के लिए पहले की तुलना में एक दूसरे के लिए और इसके विपरीत। – gauteh

5

हो सकता है कि 12 विभिन्न सरणी मूल्यों के साथ इस उदाहरण में मदद मिलेगी:

In [207]: x=np.arange(12).reshape(3,4).copy() 

In [208]: x.flags 
Out[208]: 
    C_CONTIGUOUS : True 
    F_CONTIGUOUS : False 
    OWNDATA : True 
    ... 
In [209]: x.T.flags 
Out[209]: 
    C_CONTIGUOUS : False 
    F_CONTIGUOUS : True 
    OWNDATA : False 
    ... 

C order मूल्यों आदेश है कि वे में उत्पन्न किया गया में हैं स्थानांतरित कर लोगों

In [212]: x.reshape(12,) # same as x.ravel() 
Out[212]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) 

In [213]: x.T.reshape(12,) 
Out[213]: array([ 0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11]) 

नहीं हैं तो आपको मिल सकता है।

In [214]: x1=x.T 

In [217]: x.shape=(12,) 

x सी के आकार के 1 डी विचार एक भी बदला जा सकता है।

In [220]: x1.shape=(12,) 
--------------------------------------------------------------------------- 
AttributeError       Traceback (most recent call last) 
<ipython-input-220-cf2b1a308253> in <module>() 
----> 1 x1.shape=(12,) 

AttributeError: incompatible shape for a non-contiguous array 

लेकिन हस्तांतरण का आकार बदला नहीं जा सकता है। data अभी भी 0,1,2,3,4... ऑर्डर में है, जिसे 1 डी सरणी में 0,4,8... के रूप में एक्सेस नहीं किया जा सकता है।

लेकिन x1 की एक प्रति बदला जा सकता है:

In [227]: x2=x1.copy() 

In [228]: x2.flags 
Out[228]: 
    C_CONTIGUOUS : True 
    F_CONTIGUOUS : False 
    OWNDATA : True 
    ... 
In [229]: x2.shape=(12,) 

strides को देखते हुए भी मदद कर सकता है। एक कदम यह है कि (बाइट्स में) इसे अगले मूल्य तक पहुंचने के लिए कितना कदम उठाना है। एक 2d सरणी के लिए, वहाँ हो जाएगा 2 कदम मान:

In [233]: x=np.arange(12).reshape(3,4).copy() 

In [234]: x.strides 
Out[234]: (16, 4) 

अगली पंक्ति के लिए प्राप्त करने के लिए, कदम 16 बाइट्स, अगले कॉलम केवल 4.

In [235]: x1.strides 
Out[235]: (4, 16) 

पक्षांतरित बस के आदेश स्विच प्रगति।अगली पंक्ति केवल 4 बाइट्स है- यानी अगली संख्या।

In [236]: x.shape=(12,) 

In [237]: x.strides 
Out[237]: (4,) 

आकार भी बदल रहा है बदल जाता प्रगति - बस एक समय में बफर के माध्यम से 4 बाइट कदम।

In [238]: x2=x1.copy() 

In [239]: x2.strides 
Out[239]: (12, 4) 

भी x2 हालांकि अभी x1 तरह लग रहा है, यह अपने आप डेटा बफर है, एक अलग क्रम में मूल्यों के साथ। अगला कॉलम अब 4 बाइट्स है, जबकि अगली पंक्ति 12 (3 * 4) है।

In [240]: x2.shape=(12,) 

In [241]: x2.strides 
Out[241]: (4,) 

और x साथ के रूप में 1 दिन के लिए आकार को बदलने (4,) को प्रगति कम कर देता है।

x1 के लिए, 0,1,2,... क्रम में डेटा के साथ, 1 डी ट्राइड नहीं है जो 0,4,8... देगा।

In [242]: x1.__array_interface__ 
Out[242]: 
{'strides': (4, 16), 
'typestr': '<i4', 
'shape': (4, 3), 
'version': 3, 
'data': (163336056, False), 
'descr': [('', '<i4')]} 

x1 डेटा बफर पता x, जिसके साथ यह डेटा के शेयरों के लिए के रूप में ही होगा:

__array_interface__ सरणी जानकारी प्रदर्शित करने का एक और उपयोगी तरीका है। x2 में एक अलग बफर पता है।

आप order='F' पैरामीटर copy और reshape आदेशों को जोड़ने के साथ भी प्रयोग कर सकते हैं।

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