python - تحديد قيم مكررة في مصفوفة




numpy duplicates unique (8)

لنفترض أن لدي مصفوفة

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

كيف يمكنني (بكفاءة ، Pythonically) العثور على أي عناصر من التكرارات (أي القيم غير الفريدة)؟ في هذه الحالة ستكون النتيجة array([1, 3, 3]) أو ربما array([1, 3]) إذا كانت فعالة.

لقد توصلت إلى بعض الأساليب التي يبدو أنها تعمل:

اخفاء

m = np.zeros_like(a, dtype=bool)
m[np.unique(a, return_index=True)[1]] = True
a[~m]

مجموعة العمليات

a[~np.in1d(np.arange(len(a)), np.unique(a, return_index=True)[1], assume_unique=True)]

هذا واحد لطيف ولكن ربما غير قانوني (كما ليست فريدة من نوعها في الواقع):

np.setxor1d(a, np.unique(a), assume_unique=True)

رسوم بيانية

u, i = np.unique(a, return_inverse=True)
u[np.bincount(i) > 1]

فرز

s = np.sort(a, axis=None)
s[:-1][s[1:] == s[:-1]]

الباندا

s = pd.Series(a)
s[s.duplicated()]

هل هناك أي شيء فاتني؟ أنا لا أبحث بالضرورة عن حل مستحيل فقط ، ولكن يجب أن يعمل مع أنواع بيانات غير محسوبة وأن يكون فعالاً على مجموعات البيانات متوسطة الحجم (حتى 10 ملايين في الحجم).

الاستنتاجات

اختبار مع مجموعة بيانات بحجم 10 مليون (على Xeon بسرعة 2.8 جيجا هرتز):

a = np.random.randint(10**7, size=10**7)

الأسرع هو الفرز ، في 1.1s. يأتي xor1d المشكوك فيه في xor1d الثاني عند 2.6 ثانية ، متبوعًا Series.duplicated في 3.1s ، bincount في ذلك 5.6 في ، و in1d و senderle's setdiff1d كلاهما في 7.3s. عدّ Steven's فقط أبطأ قليلا ، في 10.5s؛ تتخلف Counter.most_common عن Counter.most_common في Counter.most_common والطرح Counter DSM في 360s.

سأستخدم الفرز للأداء ، لكنني أقبل إجابة ستيفن لأن الأداء مقبول ويشعر أكثر وضوحًا وأكثر بيثونية.

تحرير: اكتشفت الحل الباندا. إذا كان Pandas متاحًا فهو واضح ويؤدي أداءً جيدًا.


Answers

اعتبارًا من الإصدار numpy الإصدار 1.9.0 ، يحتوي np.unique على وسيطة return_counts التي تبسط مهمتك بشكل كبير:

u, c = np.unique(a, return_counts=True)
dup = u[c > 1]

يشبه هذا استخدام Counter ، إلا أن تحصل على زوج من صفائف بدلاً من تعيين. سأكون فضولية لرؤية كيفية أدائهم لبعضهم البعض.


لبيثون 2.7+

>>> import numpy
>>> from collections import Counter
>>> n = numpy.array([1,1,2,3,3,3,0])
>>> [x[1] for x in Counter(n).most_common() if x[0] > 1]
[3, 1]

إذا كان المصفوفة مصفوفة متقطعة مصنفة ، فما عليك سوى القيام بما يلي:

a = np.array([1, 2, 2, 3, 4, 5, 5, 6])
rep_el = a[np.diff(a) == 0]

إليك مقاربة أخرى باستخدام العمليات المحددة التي أعتقد أنها أكثر وضوحًا من تلك التي تقدمها:

>>> indices = np.setdiff1d(np.arange(len(a)), np.unique(a, return_index=True)[1])
>>> a[indices]
array([1, 3, 3])

أفترض أنك تسأل عن حلول numpy فقط ، لأنه إذا لم يكن الأمر كذلك ، فمن الصعب المجادلة باستخدام مجرد استخدام Counter بدلاً من ذلك. أعتقد أنك يجب أن تجعل هذا الشرط صريحًا على الرغم من ذلك.


اقترح الأشخاص بالفعل تنويعات Counter ، لكن هناك واحدًا لا يستخدم قائمة listlist:

>>> from collections import Counter
>>> a = [1, 2, 1, 3, 3, 3, 0]
>>> (Counter(a) - Counter(set(a))).keys()
[1, 3]

[أرسلت ليس لأنها فعالة - انها ليست - ولكن لأنني أعتقد أنه من الرائع أن يمكنك طرح مثيلات Counter .]


إذا كان مكونًا من أرقام صحيحة صغيرة ، يمكنك استخدام numpy.bincount مباشرة:

import numpy as np

a = np.array([3, 2, 2, 0, 4, 3])
counts = np.bincount(a)
print np.where(counts > 1)[0]
# array([2, 3])

هذا يشبه إلى حد كبير طريقة "الرسم البياني" ، وهي الطريقة التي سأستخدمها إذا لم تكن مصنوعة من أعداد صحيحة صغيرة.


أعتقد أن هذا هو أكثر وضوحا القيام به خارج numpy . سيكون عليك أن numpy الحلول numpy الخاصة بك إذا كنت مهتمًا بالسرعة.

>>> import numpy as np
>>> from collections import Counter
>>> a = np.array([1, 2, 1, 3, 3, 3, 0])
>>> [item for item, count in Counter(a).iteritems() if count > 1]
[1, 3]

ملاحظة: هذا مشابه لإجابة برهان خالد ، لكن استخدام iteritems بدون اشتراك في الشرط يجب أن يكون أسرع.


يمكنك أيضًا استخدام sugar.js:

[1,2,2,3,1].unique() // => [1,2,3]

[{id:5, name:"Jay"}, {id:6, name:"Jay"}, {id: 5, name:"Jay"}].unique('id') 
  // => [{id:5, name:"Jay"}, {id:6, name:"Jay"}]




python numpy duplicates unique