2009-12-26 15 views
23

से पंक्तियों का चयन करना मैं दूसरे कॉलम में मान के आधार पर NumPy सरणी से केवल कुछ पंक्तियों का चयन करना चाहता हूं। उदाहरण के लिए, इस परीक्षण सरणी में दूसरे कॉलम में 1 से 10 के पूर्णांक हैं।NumPy ndarray

>>> test = numpy.array([numpy.arange(100), numpy.random.randint(1, 11, 100)]).transpose() 
>>> test[:10, :] 
array([[ 0, 6], 
     [ 1, 7], 
     [ 2, 10], 
     [ 3, 4], 
     [ 4, 1], 
     [ 5, 10], 
     [ 6, 6], 
     [ 7, 4], 
     [ 8, 6], 
     [ 9, 7]]) 

यदि मैं केवल पंक्तियों जहां दूसरी मान 4 है चाहता था, यह आसान है:

>>> test[test[:, 1] == 4] 
array([[ 3, 4], 
     [ 7, 4], 
     [16, 4], 
     ... 
     [81, 4], 
     [83, 4], 
     [88, 4]]) 

लेकिन मैं एक ही परिणाम कैसे प्राप्त करते हैं जब वहाँ है एक से अधिक मूल्य चाहते थे?

वांछित सूची मनमाने ढंग से लंबाई का हो सकता है। उदाहरण के लिए, मैं सभी पंक्तियों चाहते हो सकता है, जहां दूसरे स्तंभ या तो 2, 4 या 6 है:

>>> wanted = [2, 4, 6] 

एक ही रास्ता मैं के साथ आए हैं सूची समझ का उपयोग करने के लिए और फिर एक सरणी में इस वापस परिवर्तित है और लगता है बहुत गड़बड़, हालांकि यह काम करता है:

>>> test[numpy.array([test[x, 1] in wanted for x in range(len(test))])] 
array([[ 0, 6], 
     [ 3, 4], 
     [ 6, 6], 
     ... 
     [90, 2], 
     [91, 6], 
     [92, 2]]) 

क्या न्यूमपी में ऐसा करने का कोई बेहतर तरीका है कि मुझे याद आ रही है?

उत्तर

16
test[numpy.logical_or.reduce([test[:,1] == x for x in wanted])] 

परिणाम के बाद से NumPy के अजगर के बजाय आंतरिक छोरों कर मूल संस्करण की तुलना में तेजी से किया जाना चाहिए।

+0

यह समाधान सरणी लेन (वांछित) समय के माध्यम से चला जाता है। एक ही पास में सरणी के माध्यम से जाना आमतौर पर तेज़ होता है। – EOL

+0

धन्यवाद अम्नोन। यह वह समाधान है जिसे मैंने स्वीकार करने का फैसला किया।मुझे लगता है कि यह समझना स्पष्ट है और मेरे मूल समाधान से लगभग 20 x तेज है। –

+0

क्या होगा यदि मैं स्तंभ में सशर्त मूल्यों के साथ कुछ पंक्तियों का चयन करना चाहता हूं? उदाहरण के लिए, मैं उन सभी पंक्तियों का चयन करना चाहता हूं जिनके स्तंभ 1 में 5 से 10 की सीमा में मूल्य हैं। 'परीक्षण [परीक्षण [:, 1]> 4 और परीक्षण [:, 1] <8] '। – Shyamkkhadka

28

निम्नलिखित समाधान wanted रूप अम्नोन के समाधान की तुलना में तेजी से किया जाना चाहिए बड़ा हो जाता है:

wanted_set = set(wanted) # Much faster look up than with lists, for larger lists 

@numpy.vectorize 
def selected(elmt): return elmt in wanted_set # Or: selected = numpy.vectorize(wanted_set.__contains__) 

print test[selected(test[:, 1])] 

वास्तव में, यह (len(wanted) बार के बजाय) test सरणी केवल एक बार के माध्यम से खोज का लाभ दिया है। यह सेट में पाइथन के अंतर्निर्मित फास्ट एलिमेंट लुकअप का भी उपयोग करता है, जो सूचियों के मुकाबले बहुत तेज़ है। यह भी तेज़ है क्योंकि यह नम्पी के फास्ट लूप का उपयोग करता है। आपको in ऑपरेटर का अनुकूलन भी मिलता है: एक बार wanted तत्व मिलान होने के बाद, शेष तत्वों का परीक्षण नहीं किया जाना चाहिए (जैसा कि "तार्किक या" अम्नोन के दृष्टिकोण के विपरीत, wanted में सभी तत्व परीक्षण किए गए हैं, चाहे कोई भी हो) ।

test[numpy.apply_along_axis(lambda x: x[1] in wanted, 1, test)] 

यह बहुत बहुत धीमी है, हालांकि है, के रूप में यह प्रत्येक में दूसरे कॉलम में तत्व निकालता है:

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

+0

ये समाधान numpy की तुलना का उपयोग करने के बजाय प्रत्येक तत्व के लिए पायथन कहते हैं। मेरे परीक्षणों के मुताबिक, आपका पहला समाधान लेंस (वांछित) = 50 के लिए मेरे मुकाबले तेज है लेकिन लेन (वांछित) = 5 के लिए धीमा है। – Amnon

+0

ईओएल, आपके समय और प्रयास के लिए बहुत धन्यवाद। आपकी व्याख्या स्पष्ट थी। मैंने अम्नोन के समाधान का उपयोग करना चुना क्योंकि मेरे सामान्य परिदृश्य (लेन (परीक्षण) के बारे में 1000 और लेन (वांछित) लगभग 3-5), जो आपके पहले समाधान से तेज़ था। गति अंतर बड़ा नहीं है, लेकिन मुझे यह भी स्पष्ट मिला। लेकिन यह numpy के vectorize की याद दिलाना अच्छा था और मुझे यकीन है कि मैं जल्द ही इसका उपयोग करूँगा। –

+0

@ अमन: अच्छा बिंदु, और दिलचस्प परिणाम। धन्यवाद! – EOL

0

इस लेन (परीक्षण) = 1000 के लिए अम्नोन के संस्करण की तुलना में दो गुना तेजी से है:

print test[numpy.in1d(test[:,1], wanted)] 

यह आसानी से सबसे तेजी से समाधान करता है, तो होना चाहिए:

wanted = (2,4,6) 
wanted2 = numpy.expand_dims(wanted, 1) 
print test[numpy.any(test[:, 1] == wanted2, 0), :] 
+1

@ahatchkins: आपके संस्करण में कुछ टाइपो। क्या आप सुझाव दे रहे हैं यह है - # परिवर्तित एक एक स्तंभ सरणी चाहता था = numpy.array में सूची चाहता था (चाहता था) .reshape ((लेन (चाहता था), 1)) # प्रिंट परीक्षण [numpy.any (परीक्षण [:, 1] == चाहता था, 0)] मेरे परीक्षणों में, यह अम्नोन के समाधान से लगभग 2 गुना तेज है। –

+0

हां, एक टाइपो था: एस/वांछित 2/चाहता /। फिक्स्ड –

+0

हम्म, हां। तुम सही हो। वास्तव में दो typos। और केवल 2 गुना तेजी से।) –

9

numpy.in1d आप के लिए क्या देख रहे है चाहता था बड़ा है; इसके अलावा, आईडी सबसे ज्यादा पढ़ने योग्य है।