अंकों की सूची का उपयोग करके प्रति पंक्ति विशिष्ट कॉलम इंडेक्स का चयन करना


94

मैं एक NumPy मैट्रिक्स की प्रति पंक्ति विशिष्ट कॉलम का चयन करने के लिए संघर्ष कर रहा हूं।

मान लीजिए कि मेरे पास निम्नलिखित मैट्रिक्स हैं जिन्हें मैं कॉल करूंगा X:

[1, 2, 3]
[4, 5, 6]
[7, 8, 9]

मेरे पास listप्रत्येक पंक्ति में एक कॉलम इंडेक्स भी है जिसे मैं कॉल करूंगा Y:

[1, 0, 2]

मुझे मान प्राप्त करने की आवश्यकता है:

[2]
[4]
[9]

listइंडेक्स के बजाय Y, मैं उसी आकार के साथ एक मैट्रिक्स भी बना सकता हूं, Xजहां प्रत्येक कॉलम 0-1 मान में bool/ ए है int, यह दर्शाता है कि क्या यह आवश्यक कॉलम है।

[0, 1, 0]
[1, 0, 0]
[0, 0, 1]

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

मैं इस तरह सोच रहा था कि क्या कोई बेहतर उपाय है?


क्या जवाब आपके लिए बेहतर है? stackoverflow.com/a/17081678/5046896
गोइंगमवाय

जवाबों:


104

यदि आपको बूलियन एरे मिला है तो आप इस तरह से सीधे चयन कर सकते हैं:

>>> a = np.array([True, True, True, False, False])
>>> b = np.array([1,2,3,4,5])
>>> b[a]
array([1, 2, 3])

अपने प्रारंभिक उदाहरण के साथ जाने के लिए आप निम्नलिखित कार्य कर सकते हैं:

>>> a = np.array([[1,2,3], [4,5,6], [7,8,9]])
>>> b = np.array([[False,True,False],[True,False,False],[False,False,True]])
>>> a[b]
array([2, 4, 9])

आप इसमें जोड़ भी सकते हैं arangeऔर उस पर सीधा चयन भी कर सकते हैं , हालांकि यह इस बात पर निर्भर करता है कि आप अपने बूलियन एरे को कैसे पैदा कर रहे हैं और आपका कोड YMMV जैसा दिखता है।

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

आशा है कि मदद करता है, मुझे पता है अगर आप किसी भी अधिक प्रश्न हैं।


13
उदाहरण का उपयोग करने के लिए +1 arange। यह विशेष रूप से मेरे लिए कई
मैट्रिस

1
नमस्ते, क्या आप बता सकते हैं कि हमें arangeइसके बजाय उपयोग क्यों करना है :? मुझे पता है कि आपका रास्ता काम करता है और मेरा नहीं है, लेकिन मैं यह समझना चाहूंगा कि क्यों।
marcotama

@tamzord क्योंकि यह एक सुपीरियर एरे है और वनीला पाइथन लिस्ट नहीं है, इसलिए :सिंटैक्स उसी तरह काम नहीं करता है।
स्लाटर विक्टोरॉफ

1
@SlaterTyranus, प्रतिक्रिया के लिए धन्यवाद। मेरी समझ, कुछ पढ़ने के बाद, यह है कि :उन्नत अनुक्रमण के साथ मिश्रण का अर्थ है: "हर उप-स्थान के लिए :, दिए गए उन्नत अनुक्रमण को लागू करें"। क्या मेरी समझ सही है?
मार्कोटामा

@tamzord समझाता है कि "उप-अंतरिक्ष" से आपका क्या मतलब है
स्लाटर विक्टोरॉफ

36

आप ऐसा कुछ कर सकते हैं:

In [7]: a = np.array([[1, 2, 3],
   ...: [4, 5, 6],
   ...: [7, 8, 9]])

In [8]: lst = [1, 0, 2]

In [9]: a[np.arange(len(a)), lst]
Out[9]: array([2, 4, 9])

बहु-आयामी सरणियों को अनुक्रमित करने पर अधिक: http://docs.scipy.org/doc/numpy/user/basics.indexing.html#indexing-multi-dimunning-arrays


2
यह समझने के लिए संघर्ष करना चाहिए कि व्यवस्था को बस ':' या श्रेणी के बजाय क्यों आवश्यक है।
मैडमलीन

@MadmanLee हाय, परिणाम के :कई len(a)बार आउटपुट का उपयोग करेगा , इसके बजाय, प्रत्येक पंक्ति के सूचकांक का संकेत प्रत्याशित परिणामों को प्रिंट करेगा।
गोइंग मैयवे

1
मुझे लगता है कि इस समस्या को हल करने का यह सही और सुरुचिपूर्ण तरीका है।
गोइंगमवाय

6

एक सरल तरीका लग सकता है:

In [1]: a = np.array([[1, 2, 3],
   ...: [4, 5, 6],
   ...: [7, 8, 9]])

In [2]: y = [1, 0, 2]  #list of indices we want to select from matrix 'a'

range(a.shape[0]) वापस होगा array([0, 1, 2])

In [3]: a[range(a.shape[0]), y] #we're selecting y indices from every row
Out[3]: array([2, 4, 9])

1
कृपया, स्पष्टीकरण जोड़ने पर विचार करें।
सूकी

@souki मैंने अब स्पष्टीकरण जोड़ा है। धन्यवाद
धवल Mayatra

6

हाल के numpyसंस्करणों ने एक take_along_axis(और put_along_axis) जोड़ा है जो इस अनुक्रमण को सफाई से करता है।

In [101]: a = np.arange(1,10).reshape(3,3)                                                             
In [102]: b = np.array([1,0,2])                                                                        
In [103]: np.take_along_axis(a, b[:,None], axis=1)                                                     
Out[103]: 
array([[2],
       [4],
       [9]])

यह उसी तरह से संचालित होता है:

In [104]: a[np.arange(3), b]                                                                           
Out[104]: array([2, 4, 9])

लेकिन विभिन्न अक्ष संभाल के साथ। यह विशेष रूप से argsortऔर के परिणामों को लागू करने के उद्देश्य से है argmax


3

आप इट्रेटर का उपयोग करके कर सकते हैं। ऐशे ही:

np.fromiter((row[index] for row, index in zip(X, Y)), dtype=int)

समय:

N = 1000
X = np.zeros(shape=(N, N))
Y = np.arange(N)

#@Aशwini चhaudhary
%timeit X[np.arange(len(X)), Y]
10000 loops, best of 3: 30.7 us per loop

#mine
%timeit np.fromiter((row[index] for row, index in zip(X, Y)), dtype=int)
1000 loops, best of 3: 1.15 ms per loop

#mine
%timeit np.diag(X.T[Y])
10 loops, best of 3: 20.8 ms per loop

1
ओपी ने उल्लेख किया कि यह बड़े एरेज़ पर तेजी से चलना चाहिए , इसलिए आपके बेंचमार्क बहुत प्रतिनिधि नहीं हैं। मैं उत्सुक हूं कि आपकी अंतिम विधि (बड़ी) बड़ी सरणियों के लिए कैसा प्रदर्शन करती है!

@moarningsun: अपडेट किया गया। np.diag(X.T[Y])इतना धीमा है ... लेकिन np.diag(X.T)इतना तेज (10us) है। मुझे पता नहीं क्यों।
केई मिनगावा

0

एक और चतुर तरीका यह है कि पहले सरणी को स्थानांतरित करें और उसके बाद इसे अनुक्रमित करें। अंत में, विकर्ण लें, इसका हमेशा सही उत्तर।

X = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
Y = np.array([1, 0, 2, 2])

np.diag(X.T[Y])

क्रमशः:

मूल सरणियाँ:

>>> X
array([[ 1,  2,  3],
       [ 4,  5,  6],
       [ 7,  8,  9],
       [10, 11, 12]])

>>> Y
array([1, 0, 2, 2])

इसे सही अनुक्रमित करना संभव बनाने के लिए संक्रमण।

>>> X.T
array([[ 1,  4,  7, 10],
       [ 2,  5,  8, 11],
       [ 3,  6,  9, 12]])

Y क्रम में पंक्तियाँ प्राप्त करें।

>>> X.T[Y]
array([[ 2,  5,  8, 11],
       [ 1,  4,  7, 10],
       [ 3,  6,  9, 12],
       [ 3,  6,  9, 12]])

विकर्ण अब स्पष्ट हो जाना चाहिए।

>>> np.diag(X.T[Y])
array([ 2,  4,  9, 12]

1
यह तकनीकी रूप से काम करता है और बहुत सुंदर दिखता है। हालाँकि, मुझे पता है कि जब आप बड़े सरणियों के साथ काम कर रहे होते हैं तो यह दृष्टिकोण पूरी तरह से विस्फोट हो जाता है। मेरे मामले में, NumPy ने 30GB स्वैप निगल लिया और मेरा SSD भर दिया। मैं इसके बजाय उन्नत अनुक्रमण दृष्टिकोण का उपयोग करने की सलाह देता हूं।
5nefarious 19
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.