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




numpy duplicates (6)

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

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 متاحًا فهو واضح ويؤدي أداءً جيدًا.


أعتقد أن هذا هو أكثر وضوحا القيام به خارج 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 بدون اشتراك في الشرط يجب أن يكون أسرع.


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

import numpy as np

A = np.array([1,2,3,4,4,4,5,6,6,7,8])

# Record the indices where each unique element occurs.
list_of_dup_inds = [np.where(a == A)[0] for a in np.unique(A)]

# Filter out non-duplicates.
list_of_dup_inds = filter(lambda inds: len(inds) > 1, list_of_dup_inds)

for inds in list_of_dup_inds: print inds, A[inds]
# >> [3 4 5] [4 4 4]
# >> [7 8] [6 6]

إذا كان مكونًا من أرقام صحيحة صغيرة ، يمكنك استخدام 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])

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


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

>>> 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 .]


لبيثون 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]






unique