2011-12-23 11 views
6

क्या numpy में अद्वितीय तत्व प्राप्त करने का कोई तेज़ तरीका है? मैं यह एक उदाहरण मात्र है और मेरी स्थिति में indices1, indices2,...,indices4 सूचकांक के विभिन्न सेट होता है और विभिन्न आकार इस के समान कोड (अंतिम पंक्ति)फास्ट डुप्लिकेट्स numpy और python में हटाने

tab = numpy.arange(100000000) 

indices1 = numpy.random.permutation(10000) 
indices2 = indices1.copy() 
indices3 = indices1.copy() 
indices4 = indices1.copy() 

result = numpy.unique(numpy.array([tab[indices1], tab[indices2], tab[indices3], tab[indices4]])) 

है। आखिरी पंक्ति कई बार निष्पादित की जाती है और इनकॉइड किया जाता है कि यह वास्तव में मेरे कोड में बाधा है ({numpy.core.multiarray.arange} प्रीसीसिव होने के लिए)। इसके अलावा, आदेश महत्वपूर्ण नहीं है और इंडेक्स सरणी में तत्व int32 प्रकार का है। मैं तत्व मूल्य के साथ हैशटेबल का उपयोग करने के बारे में सोच रहा था और कोशिश की:

seq = itertools.chain(tab[indices1].flatten(), tab[indices2].flatten(), tab[indices3].flatten(), tab[indices4].flatten()) 
myset = {} 
map(myset.__setitem__, seq, []) 
result = numpy.array(myset.keys()) 

लेकिन यह और भी बदतर था।

क्या इसे गति देने का कोई तरीका है? मुझे लगता है कि प्रदर्शन जुर्माना 'फैंसी इंडेक्सिंग' से आता है जो सरणी की प्रतिलिपि बनाता है लेकिन मुझे परिणामस्वरूप तत्व केवल पढ़ने के लिए चाहिए (मैं कुछ भी संशोधित नहीं करता)।

+1

कितनी तेजी से इसे एक सेट में परिवर्तित कर देगा, और फिर एक numpy सरणी में वापस आ जाएगा? – FakeRainBrigand

+0

मैंने इस विधि की जांच की है और यह वास्तव में लगभग 20% खराब – pzo

उत्तर

3

खेद है कि मैं पूरी तरह से अपने प्रश्न समझ में नहीं आता है, लेकिन मैं मदद करने के लिए अपनी पूरी कोशिश करूंगा।

मुट्ठी {numpy.core.multiarray.arange} numpy.arange फैंसी इंडेक्सिंग नहीं है, दुर्भाग्य से फैंसी इंडेक्सिंग प्रोफाइलर में एक अलग लाइन आइटम के रूप में दिखाई नहीं देती है। यदि आप लूप में np.arange को कॉल कर रहे हैं, तो देखना चाहिए कि क्या आप इसे बाहर ले जा सकते हैं या नहीं।

In [27]: prun tab[tab] 
    2 function calls in 1.551 CPU seconds 

Ordered by: internal time 

ncalls tottime percall cumtime percall filename:lineno(function) 
    1 1.551 1.551 1.551 1.551 <string>:1(<module>) 
    1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 

In [28]: prun numpy.arange(10000000) 
    3 function calls in 0.051 CPU seconds 

Ordered by: internal time 

ncalls tottime percall cumtime percall filename:lineno(function) 
    1 0.047 0.047 0.047 0.047 {numpy.core.multiarray.arange} 
    1 0.003 0.003 0.051 0.051 <string>:1(<module>) 
    1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 

दूसरा मुझे लगता है कि tab मान क्योंकि यह tab[index] == index + a से है अगर, अपने कोड में np.arange(a, b) नहीं है, लेकिन मुझे लगता है कि सिर्फ अपने उदाहरण के लिए किया गया था।

तीसरा, np.concatenate के बारे में 10 बार की तुलना में तेजी है np.array

In [47]: timeit numpy.array([tab[indices1], tab[indices2], tab[indices3], tab[indices4]]) 
100 loops, best of 3: 5.11 ms per loop 

In [48]: timeit numpy.concatenate([tab[indices1], tab[indices2], tab[indices3],  tab[indices4]]) 
1000 loops, best of 3: 544 us per loop 

(इसके अलावा np.concatenate एक (4 * एन,) सरणी देता है और np.array एक (4, एन देता है) सरणी, जहां सूचकांक [1-4] की लंबाई है। उत्तरार्द्ध केवल तभी काम करेगा यदि सूचकांक 1-4 समान लंबाई हैं।)

और आखिरकार, यदि आप कर सकते हैं तो आप और भी समय बचा सकते हैं निम्नलिखित:

indices = np.unique(np.concatenate((indices1, indices2, indices3, indices4))) 
result = tab[indices] 

इसे करने से मैं n यह आदेश तेज़ है क्योंकि आप टैब में देखने के लिए आवश्यक इंडेक्स की संख्या को कम करते हैं, लेकिन यह केवल तभी काम करेगा यदि आप जानते हैं कि टैब के तत्व अद्वितीय हैं (अन्यथा आप परिणाम में दोहरा सकते हैं भले ही सूचकांक अद्वितीय हों)।

आशा है कि

+1

+1। इस विधि को मनमाने ढंग से इनपुट सरणी 'टैब' के सामान्य मामले में काम करने के लिए, मैं केवल' परिणाम = np.unique (टैब [np.unique (np.concatenate ((indices1, ...)) करने का सुझाव दूंगा) ]) '। मूल प्रश्न में विधि के रूप में यह दोगुनी तेज़ है। – EOL

+0

@EOL, या यह कि एक विकल्प है अगर सूचकांक में दोहराव है, तो उस मामले में दोहराव को डुप्लिकेट करने का ओवरहेड इसके लायक हो सकता है। –

4

[क्या इस प्रकार वास्तव में आंशिक रूप से सही नहीं है (पी एस देखें):]

सभी उप-सरणियों में अद्वितीय तत्व प्राप्त करने की निम्नलिखित रास्ता बहुत तेजी से है:

seq = itertools.chain(tab[indices1].flat, tab[indices2].flat, tab[indices3].flat, tab[indices4].flat) 
result = set(seq) 

ध्यान दें कि flat (जो एक इटरेटर लौटाता है) flatten() (जो एक पूर्ण सरणी देता है) के बजाय प्रयोग किया जाता है, और set() सीधे कहा जा सकता है (map() और एक शब्दकोश, जैसे कि आपकी दूसरी विधि में) का उपयोग करने के बजाय।

>>> %timeit result = numpy.unique(numpy.array([tab[indices1], tab[indices2], tab[indices3], tab[indices4]])) 
100 loops, best of 3: 8.04 ms per loop 
>>> seq = itertools.chain(tab[indices1].flat, tab[indices2].flat, tab[indices3].flat, tab[indices4].flat) 
>>> %timeit set(seq) 
1000000 loops, best of 3: 223 ns per loop 

सेट/फ्लैट विधि इस प्रकार 40 गुना इस उदाहरण पर तेजी से होता है:

यहाँ समय परिणाम (IPython खोल में प्राप्त) कर रहे हैं।

पीएस: set(seq) का समय वास्तव में प्रतिनिधि नहीं है। वास्तव में, समय का पहला पाश seq इटरेटर खाली करता है और बाद में set() मूल्यांकन एक खाली सेट लौटाता है! सही समय परीक्षण निम्नलिखित

>>> %timeit set(itertools.chain(tab[indices1].flat, tab[indices2].flat, tab[indices3].flat, tab[indices4].flat)) 
100 loops, best of 3: 9.12 ms per loop 

जो दिखाता है कि सेट/फ्लैट विधि वास्तव में तेज़ नहीं है।

पीपीएस: यहां एमआरटीवी के सुझाव की एक (असफल) अन्वेषण है; अद्वितीय सूचकांक पहले से खोजने के लिए एक अच्छा विचार हो सकता है, लेकिन मैं इसे लागू करने के लिए एक तरह से जो ऊपर दृष्टिकोण की तुलना में तेजी है नहीं मिल सकता है:

>>> %timeit set(indices1).union(indices2).union(indices3).union(indices4) 
100 loops, best of 3: 11.9 ms per loop 
>>> %timeit set(itertools.chain(indices1.flat, indices2.flat, indices3.flat, indices4.flat)) 
100 loops, best of 3: 10.8 ms per loop 

इस प्रकार, सब अलग सूचकांक के सेट खोजने में ही काफी धीमी है ।

PPPS: numpy.unique(<concatenated array of indices>) वास्तव में 2-3 बार set(<concatenated array of indices>) से तेज है। यह बागो के उत्तर में प्राप्त गति की कुंजी है (unique(concatenate((…))))। कारण शायद यह है कि न्यूमपी अपने सरणी को अपने आप से संभालने के लिए सामान्य पाइथन (set) को NumPy arrays के साथ इंटरफेस करने से आम तौर पर तेज है।

निष्कर्ष: इस उत्तर इसलिए केवल दस्तावेजों का प्रयास है कि पूरी तरह से पालन नहीं किया जाना चाहिए, साथ ही समय iterators के साथ कोड के बारे में संभवतः उपयोगी टिप्पणी में विफल रहा है ...

+0

अद्वितीय 'indeces' ढूंढकर, फिर' टैब 'देखने के लिए उनका उपयोग करके एक और गति प्राप्त नहीं कर सका? – mtrw

+0

@mtrw: यह एक अच्छा विचार की तरह लगता है, लेकिन मुझे एक कार्यान्वयन नहीं मिल रहा है जो उत्तर में पहली विधि से तेज़ है। 'Concatenate' के लिए – EOL