74

配列があるとします

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

どの要素aが重複しているか (つまり、一意でない値) を (効率的に、Python で) 見つけるにはどうすればよいですか? この場合、結果は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)]

これはかわいいですが、おそらく違法です (a実際には一意ではないため):

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()]

見逃したものはありますか?私は必ずしも numpy のみのソリューションを探しているわけではありませんが、numpy のデータ型で動作し、中規模のデータ セット (最大 1,000 万サイズ) で効率的でなければなりません。


結論

1,000 万サイズのデータ​​ セットを使用したテスト (2.8GHz Xeon 上):

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

最速はソートで、1.1 秒です。怪しげなxor1d人は 2.6 秒で 2 位、続いてマスキングとパンダSeries.duplicatedが 3.1 秒、5.6 秒、bincountsenderlein1dsetdiff1d両方が 7.3 秒でした。スティーブンのCounterは 10.5 秒と少し遅いだけです。後ろに続いているのは、110 秒の BurhanCounter.most_commonと 360 秒の DSM のCounter減算です。

パフォーマンスのために並べ替えを使用しますが、パフォーマンスが許容範囲内であり、より明確で Pythonicに感じられるため、Steven の回答を受け入れます。

編集: Pandas ソリューションを発見しました。Pandas が利用できる場合、それは明確であり、適切に機能します。

4

9 に答える 9

35

これは、の外部で行われることが最も明確だと思いますnumpynumpy速度に関心がある場合は、ソリューションに対してタイミングを合わせる必要があります。

>>> 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).items() if count > 1]
[1, 3]

注: これはBurhan Khalidの回答に似ていますitemsが、条件に添え字を付けずに使用する方が高速です。

于 2012-07-17T18:25:45.693 に答える
12

人々はすでにCounterバリアントを提案していますが、リストコンプを使用しないものを次に示します。

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

[効率的だからではなく、そうではありませんが、インスタンスを減算できるのがかわいいと思ったからですCounter。]

于 2012-07-17T20:10:22.863 に答える
7

Python 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]
于 2012-07-17T18:02:32.603 に答える
5

が小さい整数で構成されている場合aは、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])

これはa、小さな整数で構成されていない場合に使用する「ヒストグラム」メソッドに非常に似ています。

于 2012-07-17T18:34:33.527 に答える
5

これは、あなたが提供するものよりも少し簡単だと思うセット操作を使用した別のアプローチです。

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

- のみの解決策を求めていると思います。numpyそうでない場合、Counter代わりに a を使用するだけで議論するのは非常に難しいからです。ただし、その要件を明示する必要があると思います。

于 2012-07-17T18:32:49.790 に答える
4

配列がソートされた numpy 配列である場合は、次のようにします。

a = np.array([1, 2, 2, 3, 4, 5, 5, 6])
rep_el = a[np.diff(a) == 0]
于 2015-06-15T04:12:02.757 に答える