Supposons que j'ai un tableau
a = np.array([1, 2, 1, 3, 3, 3, 0])
Comment puis-je (efficacement, Pythoniquement) trouver quels éléments de a
sont des doublons (c'est-à-dire des valeurs non uniques)? Dans ce cas, le résultat serait array([1, 3, 3])
ou éventuellement array([1, 3])
s'il est efficace.
J'ai trouvé quelques méthodes qui semblent fonctionner:
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)]
Celui-ci est mignon mais probablement illégal (car a
n'est pas réellement unique):
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()]
Y a-t-il quelque chose que j'ai manqué? Je ne cherche pas nécessairement une solution uniquement numpy, mais elle doit fonctionner avec des types de données numpy et être efficace sur des ensembles de données de taille moyenne (jusqu'à 10 millions de taille).
Test avec un ensemble de données de 10 millions de tailles (sur un Xeon à 2,8 GHz):
a = np.random.randint(10**7, size=10**7)
Le tri le plus rapide, à 1,1 s. Le douteux xor1d
Est deuxième à 2,6 s, suivi du masquage et Pandas Series.duplicated
À 3,1 s, bincount
à 5,6 s et in1d
et le setdiff1d
de senderle à la fois à 7,3 s. Le Counter
de Steven est seulement un peu plus lent, à 10,5 s; derrière le Counter.most_common
de Burhan à 110 s et la soustraction Counter
de DSM à 360 s.
Je vais utiliser le tri pour les performances, mais j'accepte la réponse de Steven parce que les performances sont acceptables et cela se sent plus clair et plus Pythonic.
Edit: découvert la solution Pandas. Si Pandas est disponible, il est clair et fonctionne bien.
Je pense que c'est plus clair fait en dehors de numpy
. Vous devrez le synchroniser avec vos solutions numpy
si vous êtes soucieux de la vitesse.
>>> 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]
note: Ceci est similaire à la réponse de Burhan Khalid, mais l'utilisation de iteritems
sans indice dans la condition devrait être plus rapide.
Depuis numpy version 1.9.0, np.unique
a un argument return_counts
ce qui simplifie grandement votre tâche:
u, c = np.unique(a, return_counts=True)
dup = u[c > 1]
Ceci est similaire à l'utilisation de Counter
, sauf que vous obtenez une paire de tableaux au lieu d'un mappage. Je serais curieux de voir comment ils fonctionnent les uns par rapport aux autres.
Les gens ont déjà suggéré Counter
variantes, mais en voici une qui n'utilise pas un listcomp:
>>> from collections import Counter
>>> a = [1, 2, 1, 3, 3, 3, 0]
>>> (Counter(a) - Counter(set(a))).keys()
[1, 3]
[Publié non pas parce qu'il est efficace - ce n'est pas le cas - mais parce que je pense que c'est mignon que vous puissiez soustraire Counter
instances.]
Pour 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]
Voici une autre approche utilisant des opérations d'ensemble qui, je pense, est un peu plus simple que celles que vous proposez:
>>> indices = np.setdiff1d(np.arange(len(a)), np.unique(a, return_index=True)[1])
>>> a[indices]
array([1, 3, 3])
Je suppose que vous demandez des solutions numpy
uniquement, car si ce n'est pas le cas, il est très difficile de discuter avec simplement l'utilisation d'un Counter
à la place. Je pense que vous devriez cependant rendre cette exigence explicite.
Si a
est composé de petits entiers, vous pouvez utiliser numpy.bincount directement:
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])
C'est très similaire à votre méthode "histogramme", qui est celle que j'utiliserais si a
n'était pas composé de petits entiers.
Si le tableau est un tableau numpy trié, faites simplement:
a = np.array([1, 2, 2, 3, 4, 5, 5, 6])
rep_el = a[np.diff(a) == 0]
J'ajoute ma solution à la pile pour cette question de 3 ans parce qu'aucune des solutions ne correspond à ce que je voulais ou utilisais des bibliothèques à part numpy. Cette méthode trouve à la fois les indices des doublons et les valeurs des ensembles de doublons distinct.
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]
>>> import numpy as np
>>> a=np.array([1,2,2,2,2,3])
>>> uniques, uniq_idx, counts = np.unique(a,return_index=True,return_counts=True)
>>> duplicates = a[ uniq_idx[counts>=2] ] # <--- Get duplicates
Si vous souhaitez également récupérer les orphelins:
>>> orphans = a[ uniq_idx[counts==1] ]