Numpy.array में अद्वितीय पंक्तियाँ खोजें


199

मैं एक में अद्वितीय पंक्तियों को खोजने की जरूरत है numpy.array

उदाहरण के लिए:

>>> a # I have
array([[1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0]])
>>> new_a # I want to get to
array([[1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [1, 1, 1, 1, 1, 0]])

मुझे पता है कि मैं सरणी पर एक सेट और लूप बना सकता हूं, लेकिन मैं एक कुशल शुद्ध numpyसमाधान की तलाश कर रहा हूं । मेरा मानना ​​है कि डेटा प्रकार को शून्य पर सेट करने का एक तरीका है और फिर मैं बस उपयोग numpy.uniqueकर सकता हूं, लेकिन मैं यह पता नहीं लगा सका कि यह कैसे काम करता है।


11
पांडा के पास एक डेटाफ्रेम.प्रोड_डुप्लिकेट्स () विधि है। देखें stackoverflow.com/questions/12322779/pandas-unique-dataframe और pandas.pydata.org/pandas-docs/dev/generated/...
codeape

धन्यवाद, लेकिन मैं पांडा का उपयोग नहीं कर सकता।
अकवाल ६'१३ को


1
@ एंडी हेडन, शीर्षक के बावजूद, यह इस प्रश्न का दोहराव नहीं है। कोडपे का लिंक हालांकि एक डुप्लिकेट है।
वाई वाई तुंग

5
यह सुविधा मूल रूप से 1.13 पर आ रही है: github.com/numpy/numpy/pull/7742
Eric

जवाबों:


115

NumPy 1.13 के अनुसार, कोई भी किसी भी N- मंद सरणी में अद्वितीय मानों के चयन के लिए अक्ष का चयन कर सकता है। अद्वितीय पंक्तियाँ प्राप्त करने के लिए, कोई भी ऐसा कर सकता है:

unique_rows = np.unique(original_array, axis=0)


12
इस समारोह के साथ सावधान। np.unique(list_cor, axis=0)आपको डुप्लिकेट पंक्तियों के साथ सरणी हटा दी जाती है ; यह मूल सरणी में अद्वितीय तत्वों के लिए सरणी को फ़िल्टर नहीं करता है । यहाँ देखें , उदाहरण के लिए ..
ब्रैड सोलोमन

ध्यान दें कि यदि आप अद्वितीय पंक्तियों को पंक्ति में मानों के क्रम को अनदेखा करना चाहते हैं, तो आप पहले कॉलम में मूल सरणी को क्रमबद्ध कर सकते हैं:original_array.sort(axis=1)
mangecoeur

140

फिर भी एक और संभव उपाय

np.vstack({tuple(row) for row in a})

20
+1 यह स्पष्ट, छोटा और पाइथोनिक है। जब तक गति एक वास्तविक मुद्दा नहीं है, इस प्रकार के समाधानों को इस प्रश्न के जटिल, उच्चतर मतदान के जवाब पर वरीयता देना चाहिए।
बिल चीथम

3
अति उत्कृष्ट! घुंघराले ब्रेसिज़ या सेट () फ़ंक्शन चाल करता है।
तियान हे

2
@Greg वॉन विंकेल क्या आप ऐसा कुछ सुझा सकते हैं, जिसमें ऐसा कुछ न हो, जिससे ऑर्डर न बदले।
22

हां, लेकिन एक भी कमांड में नहीं: x = []; [x.append (tuple (r)) r में अगर tuple (r) x में नहीं]; a_unique = array (x);
ग्रेग वॉन विंकेल

1
FutureWarning से बचने के लिए, सेट को एक सूची में np.vstack(list({tuple(row) for row in AIPbiased[i, :, :]})) बदलें जैसे: FutureWarning: arrays to stack को "अनुक्रम" प्रकार जैसे सूची या टपल के रूप में पारित किया जाना चाहिए। गैर-अनुक्रम पुनरावृत्तियों के लिए समर्थन जैसे जनरेटर को NumPy 1.16 के रूप में पदावनत किया गया है और भविष्य में एक त्रुटि उत्पन्न करेगा।
लेयरमेस्टर

111

संरचित सरणियों के उपयोग का एक अन्य विकल्प एक voidप्रकार के दृश्य का उपयोग कर रहा है जो पूरी पंक्ति को एक आइटम में जोड़ता है:

a = np.array([[1, 1, 1, 0, 0, 0],
              [0, 1, 1, 1, 0, 0],
              [0, 1, 1, 1, 0, 0],
              [1, 1, 1, 0, 0, 0],
              [1, 1, 1, 1, 1, 0]])

b = np.ascontiguousarray(a).view(np.dtype((np.void, a.dtype.itemsize * a.shape[1])))
_, idx = np.unique(b, return_index=True)

unique_a = a[idx]

>>> unique_a
array([[0, 1, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0]])

EDIT नेnp.ascontiguousarray @ सेबर्ग की सिफारिश के बाद जोड़ा । यदि सरणी पहले से ही सन्निहित नहीं है, तो यह विधि को धीमा कर देगा।

संपादित करें उपरोक्त को थोड़ा स्पष्ट किया जा सकता है, शायद स्पष्टता की कीमत पर, ऐसा करके:

unique_a = np.unique(b).view(a.dtype).reshape(-1, a.shape[1])

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

a = np.random.randint(2, size=(10000, 6))

%timeit np.unique(a.view(np.dtype((np.void, a.dtype.itemsize*a.shape[1])))).view(a.dtype).reshape(-1, a.shape[1])
100 loops, best of 3: 3.17 ms per loop

%timeit ind = np.lexsort(a.T); a[np.concatenate(([True],np.any(a[ind[1:]]!=a[ind[:-1]],axis=1)))]
100 loops, best of 3: 5.93 ms per loop

a = np.random.randint(2, size=(10000, 100))

%timeit np.unique(a.view(np.dtype((np.void, a.dtype.itemsize*a.shape[1])))).view(a.dtype).reshape(-1, a.shape[1])
10 loops, best of 3: 29.9 ms per loop

%timeit ind = np.lexsort(a.T); a[np.concatenate(([True],np.any(a[ind[1:]]!=a[ind[:-1]],axis=1)))]
10 loops, best of 3: 116 ms per loop

3
बहुत बहुत धन्यवाद। यह वह उत्तर है जिसकी मुझे तलाश थी, क्या आप बता सकते हैं कि इस कदम पर क्या हो रहा है b = a.view(np.dtype((np.void, a.dtype.itemsize * a.shape[1]))):?
अकवाल

3
@Akavall यह np.voidएक पूर्ण पंक्ति में बाइट्स की संख्या के आकार के साथ आपके डेटा का एक दृश्य बना रहा है । यह दो समान है जो आपको मिलता है यदि आपके पास एस की एक सरणी है np.uint8और इसे np.uint16एस के रूप में देखें , जो हर दो कॉलम को एक एकल में जोड़ता है, लेकिन अधिक लचीला।
Jaime

3
@ जय, क्या आप np.ascontiguousarrayआम तौर पर सुरक्षित होने के लिए एक समान या जोड़ सकते हैं (मुझे पता है कि यह थोड़ा अधिक प्रतिबंधात्मक है फिर आवश्यक है, लेकिन ...)। अपेक्षा के अनुसार कार्य करने के लिए पंक्तियों को सन्निहित होना चाहिए।
सेबर्ग

2
@ConstantineEvans यह एक हालिया जोड़ है: सुपीड़ के 1.6 में, उस प्रकार के लिए लागू नहीं होने वाले मर्जोर्ट से संबंधित त्रुटि के np.uniqueएक सरणी पर चलाने की कोशिश कर np.voidरहा है। हालांकि यह 1.7 में ठीक काम करता है।
Jaime

9
यह ध्यान देने योग्य है कि अगर इस पद्धति का उपयोग फ्लोटिंग पॉइंट नंबरों के लिए किया जाता है, तो एक ऐसा कैच -0.होगा जिसकी तुलना नहीं के बराबर होगी +0., जबकि एक तत्व-बाय-एलिमेंट की तुलना में होगा -0.==+0.(जैसा कि आइवी फ्लोट मानक द्वारा निर्दिष्ट किया गया है)। देखें stackoverflow.com/questions/26782038/...
tom10

29

यदि आप टुपल्स या इसी तरह की अन्य डेटा संरचना की श्रृंखला में परिवर्तित होने के स्मृति व्यय से बचना चाहते हैं, तो आप सुपी की संरचित सरणियों का उपयोग कर सकते हैं।

चाल आपके मूल सरणी को एक संरचित सरणी के रूप में देखने के लिए है जहां प्रत्येक आइटम मूल सरणी की एक पंक्ति से मेल खाती है। यह एक प्रतिलिपि नहीं बनाता है, और काफी कुशल है।

एक त्वरित उदाहरण के रूप में:

import numpy as np

data = np.array([[1, 1, 1, 0, 0, 0],
                 [0, 1, 1, 1, 0, 0],
                 [0, 1, 1, 1, 0, 0],
                 [1, 1, 1, 0, 0, 0],
                 [1, 1, 1, 1, 1, 0]])

ncols = data.shape[1]
dtype = data.dtype.descr * ncols
struct = data.view(dtype)

uniq = np.unique(struct)
uniq = uniq.view(data.dtype).reshape(-1, ncols)
print uniq

क्या चल रहा है, यह समझने के लिए, मध्यस्थ परिणामों पर एक नज़र डालें।

एक बार जब हम चीजों को एक संरचित सरणी के रूप में देखते हैं, तो सरणी में प्रत्येक तत्व आपके मूल सरणी में एक पंक्ति है। (मूल रूप से, यह टुपल्स की सूची के समान डेटा संरचना है।)

In [71]: struct
Out[71]:
array([[(1, 1, 1, 0, 0, 0)],
       [(0, 1, 1, 1, 0, 0)],
       [(0, 1, 1, 1, 0, 0)],
       [(1, 1, 1, 0, 0, 0)],
       [(1, 1, 1, 1, 1, 0)]],
      dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8')])

In [72]: struct[0]
Out[72]:
array([(1, 1, 1, 0, 0, 0)],
      dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8')])

एक बार जब हम दौड़ेंगे numpy.unique, तो हमें एक संरचित सरणी मिलेगी:

In [73]: np.unique(struct)
Out[73]:
array([(0, 1, 1, 1, 0, 0), (1, 1, 1, 0, 0, 0), (1, 1, 1, 1, 1, 0)],
      dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8')])

फिर हमें "सामान्य" सरणी के रूप में देखने की आवश्यकता है ( _अंतिम गणना के परिणाम को संग्रहीत करता है ipython, जिसके कारण आप देख रहे हैं _.view...):

In [74]: _.view(data.dtype)
Out[74]: array([0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0])

और फिर एक 2 डी सरणी में पुनः आकार दें ( -1एक प्लेसहोल्डर है जो पंक्तियों की सही संख्या की गणना करने के लिए सुन्न बताता है, स्तंभों की संख्या दें):

In [75]: _.reshape(-1, ncols)
Out[75]:
array([[0, 1, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0]])

जाहिर है, यदि आप अधिक संक्षिप्त होना चाहते हैं, तो आप इसे इस प्रकार लिख सकते हैं:

import numpy as np

def unique_rows(data):
    uniq = np.unique(data.view(data.dtype.descr * data.shape[1]))
    return uniq.view(data.dtype).reshape(-1, data.shape[1])

data = np.array([[1, 1, 1, 0, 0, 0],
                 [0, 1, 1, 1, 0, 0],
                 [0, 1, 1, 1, 0, 0],
                 [1, 1, 1, 0, 0, 0],
                 [1, 1, 1, 1, 1, 0]])
print unique_rows(data)

जिसके परिणामस्वरूप:

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

यह वास्तव में बहुत धीमा लगता है, लगभग ट्यूपल्स का उपयोग करने जितना धीमा। इस तरह एक संरचित सरणी को क्रमबद्ध करना, धीरे-धीरे होता है।
cg

3
@cge - बड़े आकार के सरणियों के साथ इसे आज़माएं। हां, किसी सूची को छांटने की तुलना में एक संख्यात्मक सरणी को क्रमबद्ध करना धीमा है। हालाँकि ज्यादातर मामलों में गति मुख्य विचार नहीं है जहाँ आप ndarrays का उपयोग कर रहे हैं, हालाँकि। यह स्मृति उपयोग है। ट्यूपल्स की एक सूची इस समाधान की तुलना में बहुत अधिक मेमोरी का उपयोग करेगी । यहां तक ​​कि अगर आपके पास पर्याप्त मेमोरी है, तो यथोचित बड़े सरणी के साथ, इसे ट्यूपल्स की सूची में परिवर्तित करना गति लाभ की तुलना में अधिक उपरि है।
जो किंग

@cge - आह, मैंने ध्यान नहीं दिया कि आप उपयोग कर रहे थे lexsort। मुझे लगा कि आप ट्यूपल्स की सूची का उपयोग करने की बात कर रहे हैं। हाँ, lexsortशायद इस मामले में बेहतर विकल्प है। मैं इसके बारे में भूल गया, और एक अति जटिल समाधान के लिए कूद गया।
जो किंग

20

np.uniqueजब मैं इसे np.random.random(100).reshape(10,10)सभी अद्वितीय व्यक्तिगत तत्वों को देता हूं , लेकिन आप अद्वितीय पंक्तियों को चाहते हैं, तो सबसे पहले आपको उन्हें ट्यूल में रखने की आवश्यकता है:

array = #your numpy array of lists
new_array = [tuple(row) for row in array]
uniques = np.unique(new_array)

यही एकमात्र तरीका है कि मैं आपको अपने इच्छित प्रकारों को बदलने के लिए देखता हूं, और मुझे यकीन नहीं है कि यदि ट्यूपल्स में बदलने के लिए सूची पुनरावृत्ति आपके "लूपिंग नहीं" के साथ ठीक है


5
+1 यह स्पष्ट, छोटा और पाइथोनिक है। जब तक गति एक वास्तविक मुद्दा नहीं है, इस प्रकार के समाधानों को इस प्रश्न के जटिल, उच्चतर मतदान के जवाब पर वरीयता देना चाहिए।
बिल चीथम

मैं स्वीकृत समाधान पर इसे पसंद करता हूं। गति मेरे लिए कोई समस्या नहीं है क्योंकि मेरे पास केवल < 100प्रति आह्वान की पंक्तियाँ हैं। यह सटीक वर्णन करता है कि अद्वितीय ओवर रो का प्रदर्शन कैसे किया जाता है।
रेयिरेंग

4
यह वास्तव में मेरे डेटा के लिए काम नहीं करता है, uniquesइसमें अद्वितीय तत्व शामिल हैं। संभावित रूप से मुझे अपेक्षित आकार की गलतफहमी है array- क्या आप यहां अधिक सटीक हो सकते हैं?
फुआबर

@ ryan-saxe मुझे यह पसंद है कि यह pythonic है लेकिन यह एक अच्छा समाधान नहीं है क्योंकि पंक्ति को वापस लौटाया uniquesजाता है (और इसलिए पंक्तियों से अलग array)। B = np.array([[1,2],[2,1]]); A = np.unique([tuple(row) for row in B]); print(A) = array([[1, 2],[1, 2]])
जलमसरन

16

np.unique एक चपटा सरणी को छांटकर काम करता है, फिर यह देखता है कि क्या प्रत्येक आइटम पिछले के बराबर है। यह चपटा किए बिना मैन्युअल रूप से किया जा सकता है:

ind = np.lexsort(a.T)
a[ind[np.concatenate(([True],np.any(a[ind[1:]]!=a[ind[:-1]],axis=1)))]]

यह विधि ट्यूपल्स का उपयोग नहीं करती है, और यहां दिए गए अन्य तरीकों की तुलना में बहुत तेज और सरल होना चाहिए।

नोट: इस के पिछले संस्करण में [के बाद इंड का अधिकार नहीं था, जिसका अर्थ है कि गलत सूचकांक का उपयोग किया गया था। इसके अलावा, जो किंगटन एक अच्छी बात यह है कि यह मध्यवर्ती प्रतियाँ बनाती है। निम्नलिखित विधि कम बनाता है, एक हल की प्रतिलिपि बनाकर और फिर उसके विचारों का उपयोग करके:

b = a[np.lexsort(a.T)]
b[np.concatenate(([True], np.any(b[1:] != b[:-1],axis=1)))]

यह तेज है और कम मेमोरी का उपयोग करता है।

इसके अलावा, अगर आप एक ndarray में अद्वितीय पंक्तियां खोजना चाहते हैं , भले ही कितने आयाम सरणी में हैं, निम्नलिखित काम करेंगे:

b = a[lexsort(a.reshape((a.shape[0],-1)).T)];
b[np.concatenate(([True], np.any(b[1:]!=b[:-1],axis=tuple(range(1,a.ndim)))))]

एक दिलचस्प शेष मुद्दा होगा यदि आप एक मनमाना-आयाम सरणी के मनमाने अक्ष के साथ छंटनी / अद्वितीय करना चाहते हैं, तो कुछ ऐसा जो अधिक कठिन होगा।

संपादित करें:

गति के अंतर को प्रदर्शित करने के लिए, मैंने उत्तरों में वर्णित तीन अलग-अलग तरीकों के ipython में कुछ परीक्षण किए। साथ अपने सटीक एक, वहाँ बहुत ज्यादा अंतर नहीं है, हालांकि इस संस्करण थोड़ा तेजी से होता है:

In [87]: %timeit unique(a.view(dtype)).view('<i8')
10000 loops, best of 3: 48.4 us per loop

In [88]: %timeit ind = np.lexsort(a.T); a[np.concatenate(([True], np.any(a[ind[1:]]!= a[ind[:-1]], axis=1)))]
10000 loops, best of 3: 37.6 us per loop

In [89]: %timeit b = [tuple(row) for row in a]; np.unique(b)
10000 loops, best of 3: 41.6 us per loop

एक बड़े के साथ, हालांकि, यह संस्करण बहुत तेजी से समाप्त हो रहा है:

In [96]: a = np.random.randint(0,2,size=(10000,6))

In [97]: %timeit unique(a.view(dtype)).view('<i8')
10 loops, best of 3: 24.4 ms per loop

In [98]: %timeit b = [tuple(row) for row in a]; np.unique(b)
10 loops, best of 3: 28.2 ms per loop

In [99]: %timeit ind = np.lexsort(a.T); a[np.concatenate(([True],np.any(a[ind[1:]]!= a[ind[:-1]],axis=1)))]
100 loops, best of 3: 3.25 ms per loop

बहुत अच्छा! एक साइड नोट पर, हालांकि, यह कई मध्यस्थ प्रतियां बनाता है। (जैसे a[ind[1:]]एक प्रति है, आदि) दूसरी ओर, आपका समाधान आम तौर पर खदान से 2-3 गुना तेज होता है जब तक कि आप राम से बाहर नहीं निकलते।
जो किंग

अच्छी बात। जैसा कि यह पता चला है, सिर्फ अनुक्रमणिका का उपयोग करके मेरी मध्यस्थता की प्रतियों को निकालने की मेरी कोशिश ने मेरी पद्धति का अधिक मेमोरी का उपयोग किया है और सरणी के एक हल की गई प्रतिलिपि बनाने की तुलना में धीमी गति से समाप्त हो रहा है, जैसा कि a_sorted [1:] की प्रतिलिपि नहीं है a_sorted ।
cg

dtypeआपकी टाइमिंग में क्या है ? मुझे लगता है कि आपको वह गलत लगा। मेरे सिस्टम पर, np.uniqueमेरे उत्तर में वर्णित कॉलिंग आपके दो फ्लेवर्स में से किसी एक का उपयोग करने की तुलना में थोड़ा तेज है np.lexsort। और यह लगभग 5x तेज है अगर सरणी को खोजने के लिए आकार है (10000, 100)। यहां तक ​​कि अगर आप np.uniqueकुछ (मामूली) निष्पादन समय को ट्रिम करने के लिए पुन: लागू करने का निर्णय लेते हैं , तो प्रत्येक पंक्ति को एक एकल ऑब्जेक्ट में ढहाने से np.anyस्तंभों की तुलना में कॉल करने की तुलना में तेजी से तुलना होती है , विशेष रूप से उच्च स्तंभ मायने रखता है।
जैमे

@cge: आप शायद 'np.any' का मतलब मानक के बजाय 'कोई' जो कीवर्ड तर्क नहीं लेते हैं।
एम। टोया

@Jaime - मेरा मानना dtypeहै a.dtypeकि डेटा के डेटा प्रकार को देखा जा रहा है, जैसा कि उनके जवाब में जो किंगटन ने किया है। यदि कई कॉलम हैं, तो चीजों को तेजी से रखने का एक और (अपूर्ण) तरीका lexsortकेवल कुछ स्तंभों पर सॉर्ट करना है। यह डेटा-विशिष्ट है क्योंकि किसी को यह जानने की आवश्यकता है कि कौन से कॉलम पूरी तरह से सॉर्ट करने के लिए पर्याप्त भिन्नता प्रदान करते हैं। जैसे a.shape = (60000, 500)- पहले 3 कॉलम पर छाँटें ind = np.lexsort((a[:, 2], a[:, 1], a[:, 0])):। समय की बचत काफी पर्याप्त है, लेकिन फिर से अस्वीकरण: यह सभी मामलों को पकड़ नहीं सकता है - यह डेटा पर निर्भर करता है।
n1k31t4 13:21

9

यहाँ @Greg पायथोनिक उत्तर के लिए एक और भिन्नता है

np.vstack(set(map(tuple, a)))

9

मैंने गति के लिए सुझाए गए विकल्प की तुलना की है और पाया है कि, आश्चर्यजनक रूप से, शून्य दृश्य uniqueसमाधान तर्क के uniqueसाथ सुन्न के मूल की तुलना में थोड़ा तेज है axis। यदि आप गति की तलाश कर रहे हैं, तो आप चाहते हैं

numpy.unique(
    a.view(numpy.dtype((numpy.void, a.dtype.itemsize*a.shape[1])))
    ).view(a.dtype).reshape(-1, a.shape[1])

यहां छवि विवरण दर्ज करें


प्लॉट को फिर से तैयार करने के लिए कोड:

import numpy
import perfplot


def unique_void_view(a):
    return numpy.unique(
        a.view(numpy.dtype((numpy.void, a.dtype.itemsize*a.shape[1])))
        ).view(a.dtype).reshape(-1, a.shape[1])


def lexsort(a):
    ind = numpy.lexsort(a.T)
    return a[ind[
        numpy.concatenate((
            [True], numpy.any(a[ind[1:]] != a[ind[:-1]], axis=1)
            ))
        ]]


def vstack(a):
    return numpy.vstack({tuple(row) for row in a})


def unique_axis(a):
    return numpy.unique(a, axis=0)


perfplot.show(
    setup=lambda n: numpy.random.randint(2, size=(n, 20)),
    kernels=[unique_void_view, lexsort, vstack, unique_axis],
    n_range=[2**k for k in range(15)],
    logx=True,
    logy=True,
    xlabel='len(a)',
    equality_check=None
    )

1
बहुत अच्छा जवाब, एक मामूली बिंदु:, vstack_dictकभी भी एक तानाशाही का उपयोग नहीं करता है, घुंघराले ब्रेसिज़ एक सेट समझ है, और इसलिए इसका व्यवहार लगभग समान है vstatck_set। चूंकि, vstack_dictप्रदर्शन रेखा मेंढक ग्राफ के लिए गायब है, ऐसा लगता है जैसे यह vstack_setप्रदर्शन ग्राफ द्वारा कवर किया जा रहा है , क्योंकि वे बहुत समान हैं!
अकावल

उत्तर के लिए धन्यवाद। मैंने केवल एक vstackसंस्करण को शामिल करने के लिए कथानक में सुधार किया है ।
निको श्लोमर

8

मुझे इनमें से कोई भी जवाब पसंद नहीं आया क्योंकि कोई भी एक रेखीय बीजगणित या वेक्टर अंतरिक्ष अर्थ में फ्लोटिंग-पॉइंट सरणियों को नहीं संभालता है, जहां दो पंक्तियों को "बराबर" का अर्थ "कुछ some के भीतर" होता है। एक उत्तर जिसमें सहिष्णुता सीमा है, https://stackoverflow.com/a/26867764/500207 , दोनों तत्व-वार और दशमलव सटीक होने के लिए दहलीज ले ली , जो कुछ मामलों के लिए काम करता है लेकिन गणितीय रूप से सामान्य नहीं है सच वेक्टर दूरी।

यहाँ मेरा संस्करण है:

from scipy.spatial.distance import squareform, pdist

def uniqueRows(arr, thresh=0.0, metric='euclidean'):
    "Returns subset of rows that are unique, in terms of Euclidean distance"
    distances = squareform(pdist(arr, metric=metric))
    idxset = {tuple(np.nonzero(v)[0]) for v in distances <= thresh}
    return arr[[x[0] for x in idxset]]

# With this, unique columns are super-easy:
def uniqueColumns(arr, *args, **kwargs):
    return uniqueRows(arr.T, *args, **kwargs)

उपर्युक्त पब्लिक-डोमेन फ़ंक्शन प्रत्येक जोड़ी की पंक्तियों के scipy.spatial.distance.pdistबीच यूक्लिडियन (अनुकूलन योग्य) दूरी खोजने के लिए उपयोग करता है । फिर यह प्रत्येक दूरी की तुलना एक पुरानी से पुरानी पंक्तियों को खोजने के लिए करता है जो एक-दूसरे के भीतर होती हैं, और प्रत्येक -क्लस्टर से सिर्फ एक पंक्ति लौटाती हैं ।threshthreshthresh

संकेत के अनुसार, दूरी को metricयूक्लिडियन नहीं होना चाहिए - pdistविविध दूरी की गणना कर सकते हैं, जिसमें cityblock(मैनहट्टन-मानदंड) औरcosine (वैक्टर के बीच का कोण ।

यदि thresh=0(डिफ़ॉल्ट), तो पंक्तियों को "अद्वितीय" माना जाना चाहिए। threshस्केल किए गए मशीन-सटीक उपयोग के लिए अन्य अच्छे मूल्य , अर्थात thresh=np.spacing(1)*1e3


सबसे बढ़िया उत्तर। धन्यवाद। यह अब तक लिखा गया सबसे अधिक (गणितीय रूप से) सामान्यीकृत उत्तर है। यह मैट्रिक्स को एन-डायमेंशनल स्पेस में डेटा बिंदुओं या नमूनों के एक सेट के रूप में मानता है और समान या समान पॉइंट्स का एक संग्रह (समानता या तो यूक्लिडियन दूरी या किसी अन्य तरीकों से परिभाषित किया जा रहा है) का एक संग्रह पाता है। इन बिंदुओं पर अतिव्यापी डेटा बिंदु या बहुत करीबी पड़ोस हो सकते हैं। अंत में, समान या समान बिंदुओं के संग्रह को उसी सेट से संबंधित किसी भी बिंदु (उपरोक्त बिंदु पर पहले बिंदु से) द्वारा प्रतिस्थापित किया जाता है। यह एक बिंदु बादल से अतिरेक को कम करने में मदद करता है।
संचित

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

ज़रूर। इसमें कोई शक नहीं। मैंने अभी पहले बिंदु का उल्लेख किया है क्योंकि यह आपका कार्यक्रम है जो पूरी तरह से ठीक है।
संचित

बस एक सुधार - मैंने ऊपर गलत कहा कि प्रत्येक thresh-क्लस्टर के लिए जो पंक्ति उठाई जाएगी, वह अनियंत्रित प्रकृति के कारण यादृच्छिक होगी set। बेशक, मेरी ओर से एक दिमागी फितूर है, तर्जनी setके threshट्यूपल्स जो -इन्हेबोरहुड में हैं, इसलिए यह वास्तव में वापसी findRows करता है, प्रत्येक thresh-क्लस्टर के लिए, इसमें पहली पंक्ति।
अहमद फ़सीह

3

drop_duplicatesपांडा से उपयोग क्यों नहीं :

>>> timeit pd.DataFrame(image.reshape(-1,3)).drop_duplicates().values
1 loops, best of 3: 3.08 s per loop

>>> timeit np.vstack({tuple(r) for r in image.reshape(-1,3)})
1 loops, best of 3: 51 s per loop

मुझे वास्तव में यह उत्तर पसंद है। यकीन है, यह सीधे सुन्न का उपयोग नहीं करता है, लेकिन मेरे लिए यह सबसे आसान है, जबकि यह तेज है।
रात्रि 12-1217

3

Numpy_indexed पैकेज (अस्वीकरण: मैं उसके लेखक हूँ) लपेटता समाधान एक अच्छा में जैमे द्वारा पोस्ट की और परीक्षण किया गया इंटरफ़ेस, के साथ साथ कई और अधिक विशेषताएं:

import numpy_indexed as npi
new_a = npi.unique(a)  # unique elements over axis=0 (rows) by default

1

np.unique के कामों की सूची दी गई है:

>>> np.unique([(1, 1), (2, 2), (3, 3), (4, 4), (2, 2)])
Out[9]: 
array([[1, 1],
       [2, 2],
       [3, 3],
       [4, 4]])

सूचियों की सूची के साथ यह एक उठता है TypeError: unhashable type: 'list'


मेरा काम नहीं लगता है। प्रत्येक टपल दो फ़्लोट संख्या के बजाय दो तार है
एमजपी

काम नहीं करता है, यह
टुपल्स

1

इस पृष्ठ में उत्तर के आधार पर मैंने एक फ़ंक्शन लिखा है जो MATLAB के unique(input,'rows')फ़ंक्शन की क्षमता की नकल करता है, जिसमें अतिरिक्त विशेषता के साथ विशिष्टता की जांच के लिए सहिष्णुता को स्वीकार करना है। यह ऐसे c = data[ia,:]और सूचकांकों को भी लौटाता है data = c[ic,:]। कृपया रिपोर्ट करें कि क्या आपको कोई विसंगतियां या त्रुटियां दिखाई देती हैं।

def unique_rows(data, prec=5):
    import numpy as np
    d_r = np.fix(data * 10 ** prec) / 10 ** prec + 0.0
    b = np.ascontiguousarray(d_r).view(np.dtype((np.void, d_r.dtype.itemsize * d_r.shape[1])))
    _, ia = np.unique(b, return_index=True)
    _, ic = np.unique(b, return_inverse=True)
    return np.unique(b).view(d_r.dtype).reshape(-1, d_r.shape[1]), ia, ic

1

@Jaime उत्कृष्ट उत्तर से परे, एक पंक्ति को संक्षिप्त करने का एक और तरीका उपयोग करना है a.strides[0](मान aलेना C-contiguous) जो इसके बराबर है a.dtype.itemsize*a.shape[0]। इसके अलावा void(n)एक शॉर्टकट है dtype((void,n))। हम आखिरकार इस सबसे छोटे संस्करण में पहुंचे:

a[unique(a.view(void(a.strides[0])),1)[1]]

के लिये

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

0

3 डी या उच्च बहुआयामी नेस्टेड सरणियों जैसे सामान्य प्रयोजन के लिए, यह प्रयास करें:

import numpy as np

def unique_nested_arrays(ar):
    origin_shape = ar.shape
    origin_dtype = ar.dtype
    ar = ar.reshape(origin_shape[0], np.prod(origin_shape[1:]))
    ar = np.ascontiguousarray(ar)
    unique_ar = np.unique(ar.view([('', origin_dtype)]*np.prod(origin_shape[1:])))
    return unique_ar.view(origin_dtype).reshape((unique_ar.shape[0], ) + origin_shape[1:])

जो आपके 2D डेटासेट को संतुष्ट करता है:

a = np.array([[1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0]])
unique_nested_arrays(a)

देता है:

array([[0, 1, 1, 1, 0, 0],
   [1, 1, 1, 0, 0, 0],
   [1, 1, 1, 1, 1, 0]])

लेकिन यह भी 3 डी सरणियों की तरह:

b = np.array([[[1, 1, 1], [0, 1, 1]],
              [[0, 1, 1], [1, 1, 1]],
              [[1, 1, 1], [0, 1, 1]],
              [[1, 1, 1], [1, 1, 1]]])
unique_nested_arrays(b)

देता है:

array([[[0, 1, 1], [1, 1, 1]],
   [[1, 1, 1], [0, 1, 1]],
   [[1, 1, 1], [1, 1, 1]]])

unique return_indexJaime का उपयोग करते हुए उस अंतिम returnपंक्ति को सरल बनाना चाहिए । बस arसही धुरी पर मूल सूचकांक ।
hpaulj

0

इनमें से किसी भी उत्तर ने मेरे लिए काम नहीं किया। मैं अपनी अनूठी पंक्तियों को समाहित करता हूं और संख्या नहीं। हालांकि एक और सूत्र के इस जवाब ने काम किया:

स्रोत: https://stackoverflow.com/a/38461043/5402386

आप .count () और .index () सूची के तरीकों का उपयोग कर सकते हैं

coor = np.array([[10, 10], [12, 9], [10, 5], [12, 9]])
coor_tuple = [tuple(x) for x in coor]
unique_coor = sorted(set(coor_tuple), key=lambda x: coor_tuple.index(x))
unique_count = [coor_tuple.count(x) for x in unique_coor]
unique_index = [coor_tuple.index(x) for x in unique_coor]

0

हम वास्तव में mxn संख्यात्मक numpy सरणी को mx 1 numpy स्ट्रिंग सरणी में बदल सकते हैं, कृपया निम्न फ़ंक्शन का उपयोग करने का प्रयास करें, यह numpy.unique की तरह ही गिनती , व्युत्क्रम_idx और आदि प्रदान करता है :

import numpy as np

def uniqueRow(a):
    #This function turn m x n numpy array into m x 1 numpy array storing 
    #string, and so the np.unique can be used

    #Input: an m x n numpy array (a)
    #Output unique m' x n numpy array (unique), inverse_indx, and counts 

    s = np.chararray((a.shape[0],1))
    s[:] = '-'

    b = (a).astype(np.str)

    s2 = np.expand_dims(b[:,0],axis=1) + s + np.expand_dims(b[:,1],axis=1)

    n = a.shape[1] - 2    

    for i in range(0,n):
         s2 = s2 + s + np.expand_dims(b[:,i+2],axis=1)

    s3, idx, inv_, c = np.unique(s2,return_index = True,  return_inverse = True, return_counts = True)

    return a[idx], inv_, c

उदाहरण:

A = np.array([[ 3.17   9.502  3.291],
  [ 9.984  2.773  6.852],
  [ 1.172  8.885  4.258],
  [ 9.73   7.518  3.227],
  [ 8.113  9.563  9.117],
  [ 9.984  2.773  6.852],
  [ 9.73   7.518  3.227]])

B, inv_, c = uniqueRow(A)

Results:

B:
[[ 1.172  8.885  4.258]
[ 3.17   9.502  3.291]
[ 8.113  9.563  9.117]
[ 9.73   7.518  3.227]
[ 9.984  2.773  6.852]]

inv_:
[3 4 1 0 2 4 0]

c:
[2 1 1 1 2]

-1

एक सूची के रूप में संपूर्ण संख्यात्मक मैट्रिक्स प्राप्त करें, फिर इस सूची से डुप्लिकेट को छोड़ दें, और अंत में हमारी अद्वितीय सूची को एक खसखस ​​में वापस लौटाएं:

matrix_as_list=data.tolist() 
matrix_as_list:
[[1, 1, 1, 0, 0, 0], [0, 1, 1, 1, 0, 0], [0, 1, 1, 1, 0, 0], [1, 1, 1, 0, 0, 0], [1, 1, 1, 1, 1, 0]]

uniq_list=list()
uniq_list.append(matrix_as_list[0])

[uniq_list.append(item) for item in matrix_as_list if item not in uniq_list]

unique_matrix=np.array(uniq_list)
unique_matrix:
array([[1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [1, 1, 1, 1, 1, 0]])

-3

सबसे सीधा उपाय यह है कि पंक्तियों को एक तार बनाकर एक तार बना दिया जाए। प्रत्येक पंक्ति को फिर से खसरा का उपयोग करके इसकी विशिष्टता के लिए संपूर्ण के रूप में तुलना की जा सकती है। यह समाधान सामान्यीकृत है-बस आपको अन्य संयोजनों के लिए अपने सरणी को फिर से व्यवस्थित करने और स्थानांतरित करने की आवश्यकता है। यहाँ समस्या का समाधान दिया गया है।

import numpy as np

original = np.array([[1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0]])

uniques, index = np.unique([str(i) for i in original], return_index=True)
cleaned = original[index]
print(cleaned)    

दे देंगे:

 array([[0, 1, 1, 1, 0, 0],
        [1, 1, 1, 0, 0, 0],
        [1, 1, 1, 1, 1, 0]])

मेल में मेरा नोबेल पुरस्कार भेजें


बहुत अक्षम और त्रुटि प्रवण, उदाहरण के लिए अलग-अलग प्रिंट विकल्प। अन्य विकल्प स्पष्ट रूप से बेहतर हैं।
माइकल 18

-3
import numpy as np
original = np.array([[1, 1, 1, 0, 0, 0],
                     [0, 1, 1, 1, 0, 0],
                     [0, 1, 1, 1, 0, 0],
                     [1, 1, 1, 0, 0, 0],
                     [1, 1, 1, 1, 1, 0]])
# create a view that the subarray as tuple and return unique indeies.
_, unique_index = np.unique(original.view(original.dtype.descr * original.shape[1]),
                            return_index=True)
# get unique set
print(original[unique_index])
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.