एक NumPy बहुआयामी सरणी के ith कॉलम का उपयोग कैसे करें?


461

मान लीजिए कि मेरे पास है:

test = numpy.array([[1, 2], [3, 4], [5, 6]])

test[i]मुझे सरणी की ith लाइन (जैसे [1, 2]) मिलती है । मैं ith कॉलम कैसे एक्सेस कर सकता हूं ? (जैसे [1, 3, 5])। इसके अलावा, यह एक महंगा ऑपरेशन होगा?

जवाबों:


684
>>> test[:,0]
array([1, 3, 5])

इसी तरह,

>>> test[1,:]
array([3, 4])

आप पंक्तियों का उपयोग कर सकते हैं। यह NumPy संदर्भ की धारा 1.4 (अनुक्रमण) में शामिल है । यह त्वरित है, कम से कम मेरे अनुभव में। यह निश्चित रूप से लूप में प्रत्येक तत्व तक पहुंचने की तुलना में बहुत तेज है।


11
यह एक प्रति बनाता है, क्या संदर्भ प्राप्त करना संभव है, जैसे मुझे एक कॉलम का संदर्भ मिलता है, इस संदर्भ में कोई भी परिवर्तन मूल सरणी में परिलक्षित होता है।
हॉर्मोन

@ धर्म यह एक प्रति नहीं बनाता है, यह एक दृश्य बनाता है।
rinspy जू

69

और यदि आप एक बार में एक से अधिक कॉलम एक्सेस करना चाहते हैं, तो आप कर सकते हैं:

>>> test = np.arange(9).reshape((3,3))
>>> test
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
>>> test[:,[0,2]]
array([[0, 2],
       [3, 5],
       [6, 8]])

हालांकि इस मामले में आप केवल डेटा तक नहीं पहुंच रहे हैं ; आप एक कॉपी (फैंसी इंडेक्सिंग)
जॉन ग्रीनल

14
test[:,[0,2]]बस डेटा तक पहुँचता है, उदाहरण के लिए, test[:, [0,2]] = somethingपरीक्षण को संशोधित करेगा, और दूसरा सरणी नहीं बनाएगा। लेकिन copy_test = test[:, [0,2]]वास्तव में जैसा कि आप कहते हैं एक प्रति बनाएँ।
अकवाल

3
यह एक प्रति बनाता है, क्या संदर्भ प्राप्त करना संभव है, जैसे मुझे कुछ कॉलम का संदर्भ मिलता है, इस संदर्भ में कोई भी परिवर्तन मूल सरणी में परिलक्षित होता है?
हॉर्मोन

@ harman786 आप केवल संशोधित सरणी को पुराने पर पुन: असाइन कर सकते हैं।
तमोगण चौधरी

test[:,[0,2]]सिर्फ डेटा तक पहुंच क्यों test[:, [0, 2]][:, [0, 1]]नहीं है? यह बहुत ही अनपेक्षित लगता है कि एक ही काम करने का फिर से एक अलग परिणाम होता है।
Mapf

65
>>> test[:,0]
array([1, 3, 5])

यह कमांड आपको एक पंक्ति सदिश देता है, यदि आप बस उस पर लूप करना चाहते हैं, तो यह ठीक है, लेकिन यदि आप आयाम 3xN के साथ कुछ अन्य सरणी के साथ रुकना चाहते हैं, तो आपके पास होगा

ValueError: all the input arrays must have same number of dimensions

जबकि

>>> test[:,[0]]
array([[1],
       [3],
       [5]])

आपको एक कॉलम वेक्टर देता है, ताकि आप कॉन्टेनेट या हाईस्टैक ऑपरेशन कर सकें।

जैसे

>>> np.hstack((test, test[:,[0]]))
array([[1, 2, 1],
       [3, 4, 3],
       [5, 6, 5]])

1
अनुक्रमण एक समय में एक से अधिक कॉलम के साथ भी काम करता है, इसलिए अंतिम उदाहरण का परीक्षण किया जा सकता है: [, [0,1,0]] या परीक्षण [:, [श्रेणी (test.shape [1]) + [0] ]
परिवाद

5
+1 निर्दिष्ट करने के लिए [:, [0]] बनाम [:, 0] एक पंक्ति वेक्टर के बजाय एक स्तंभ वेक्टर प्राप्त करने के लिए। बिल्कुल वही व्यवहार जिसकी मुझे तलाश थी। अतिरिक्त इंडेक्सिंग नोट के लिए भी +1 एफबीआई के लिए। यह उत्तर शीर्ष उत्तर के साथ वहीं होना चाहिए।
dhj

1
यह उत्तर चुनना होगा
गुसेव स्लाव

22

आप एक पंक्ति भी स्थानांतरित और वापस कर सकते हैं:

In [4]: test.T[0]
Out[4]: array([1, 3, 5])

स्तंभों तक पहुंचने का सबसे तेज़ तरीका खोजने से पहले मैं कुछ समय के लिए ऐसा कर रहा हूं, मुझे आश्चर्य है कि क्या यह तेज, धीमा है, या परीक्षण के समान ही है [:, [0]]
जोस चमोरो


5

यद्यपि प्रश्न का उत्तर दिया गया है, लेकिन मुझे कुछ बारीकियों का उल्लेख करना चाहिए।

मान लें कि आप सरणी के पहले कॉलम में रुचि रखते हैं

arr = numpy.array([[1, 2],
                   [3, 4],
                   [5, 6]])

जैसा कि आप पहले से ही अन्य उत्तरों से जानते हैं, इसे "पंक्ति वेक्टर" (आकार की सरणी (3,)) के रूप में प्राप्त करने के लिए , आप स्लाइसिंग का उपयोग करते हैं:

arr_c1_ref = arr[:, 1]  # creates a reference to the 1st column of the arr
arr_c1_copy = arr[:, 1].copy()  # creates a copy of the 1st column of the arr

यह जाँचने के लिए कि एक सरणी एक दृश्य है या किसी अन्य सरणी की प्रतिलिपि आप निम्न कार्य कर सकते हैं:

arr_c1_ref.base is arr  # True
arr_c1_copy.base is arr  # False

ndarray.base देखें ।

दोनों के बीच स्पष्ट अंतर के अलावा (संशोधन arr_c1_refको प्रभावित करेगा arr), उनमें से प्रत्येक को ट्रैवर्स करने के लिए बाइट-चरणों की संख्या अलग है:

arr_c1_ref.strides[0]  # 8 bytes
arr_c1_copy.strides[0]  # 4 bytes

देख प्रगति । यह महत्वपूर्ण क्यों है? कल्पना करें कि आपके पास Aइसके बजाय एक बहुत बड़ी सरणी है arr:

A = np.random.randint(2, size=(10000,10000), dtype='int32')
A_c1_ref = A[:, 1] 
A_c1_copy = A[:, 1].copy()

और आप पहले कॉलम के सभी तत्वों के योग की गणना करना चाहते हैं, A_c1_ref.sum()या A_c1_copy.sum()। प्रतिलिपि किए गए संस्करण का उपयोग करना बहुत तेज़ है:

%timeit A_c1_ref.sum()  # ~248 µs
%timeit A_c1_copy.sum()  # ~12.8 µs

यह पहले उल्लिखित स्ट्राइड्स की विभिन्न संख्याओं के कारण है:

A_c1_ref.strides[0]  # 40000 bytes
A_c1_copy.strides[0]  # 4 bytes

यद्यपि यह लग सकता है कि कॉलम प्रतियों का उपयोग करना बेहतर है, यह हमेशा इस कारण से सही नहीं है कि प्रतिलिपि बनाने में समय लगता है और अधिक मेमोरी का उपयोग करता है (इस मामले में मुझे लगभग 200 using बनाने के लिए लगभग A_c1_copy) लिया गया है। हालाँकि, अगर हमें पहली जगह में कॉपी की आवश्यकता है, या हमें सरणी के एक विशिष्ट कॉलम पर कई अलग-अलग ऑपरेशन करने की आवश्यकता है और हम गति के लिए स्मृति का त्याग करने के साथ ठीक हैं, तो प्रतिलिपि बनाना एक रास्ता है।

उस स्थिति में जब हम अधिकतर स्तंभों के साथ काम करने में रुचि रखते हैं, यह पंक्ति-प्रमुख ('C') क्रम के बजाय स्तंभ-प्रमुख ('F') क्रम में हमारे सरणी बनाने के लिए एक अच्छा विचार हो सकता है (जो कि डिफ़ॉल्ट है ), और फिर एक प्रतिलिपि प्राप्त करने के बिना एक कॉलम प्राप्त करने के लिए पहले की तरह स्लाइसिंग करें:

A = np.asfortranarray(A)  # or np.array(A, order='F')
A_c1_ref = A[:, 1]
A_c1_ref.strides[0]  # 4 bytes
%timeit A_c1_ref.sum()  # ~12.6 µs vs ~248 µs

अब, कॉलम-व्यू पर राशि संचालन (या किसी अन्य) का प्रदर्शन बहुत तेज है।

अंत में मुझे ध्यान दें कि एक सरणी को ट्रांसपोज़ करना और पंक्ति-स्लाइसिंग का उपयोग करना मूल स्तंभ पर कॉलम-स्लाइसिंग का उपयोग करने के समान है, क्योंकि ट्रांसपोज़िंग केवल आकृति और मूल सरणी के स्ट्रैप को स्वैप करके किया जाता है।

A.T[1,:].strides[0]  # 40000

3
>>> test
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])

>>> ncol = test.shape[1]
>>> ncol
5L

तब आप इस तरह से 2 - 4 वां कॉलम चुन सकते हैं:

>>> test[0:, 1:(ncol - 1)]
array([[1, 2, 3],
       [6, 7, 8]])
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.