J'ai besoin de trouver des lignes uniques dans un fichier numpy.array
.
Par exemple:
>>> 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]])
Je sais que je peux créer un ensemble et une boucle sur le tableau, mais je recherche une numpy
solution pure efficace . Je crois qu'il existe un moyen de définir le type de données sur void et que je pourrais simplement l'utiliser numpy.unique
, mais je ne pouvais pas comprendre comment le faire fonctionner.
Réponses:
Depuis NumPy 1.13, on peut simplement choisir l'axe pour la sélection de valeurs uniques dans n'importe quel tableau N-dim. Pour obtenir des lignes uniques, on peut faire:
unique_rows = np.unique(original_array, axis=0)
la source
np.unique(list_cor, axis=0)
vous obtient le tableau avec les lignes en double supprimées ; il ne filtre pas le tableau en éléments uniques dans le tableau d'origine . Voir ici , par exemple ..original_array.sort(axis=1)
Encore une autre solution possible
la source
np.vstack(list({tuple(row) for row in AIPbiased[i, :, :]}))
FutureWarning: les tableaux à empiler doivent être passés en tant que type "séquence" tel que liste ou tuple. La prise en charge des itérables non séquentiels tels que les générateurs est obsolète à partir de NumPy 1.16 et générera une erreur à l'avenir.Une autre option pour l'utilisation de tableaux structurés consiste à utiliser une vue d'un
void
type qui joint la ligne entière en un seul élément:EDIT Ajouté
np.ascontiguousarray
suite à la recommandation de @ seberg. Cela ralentira la méthode si le tableau n'est pas déjà contigu.EDIT Ce qui précède peut être légèrement accéléré, peut-être au détriment de la clarté, en faisant:
De plus, au moins sur mon système, en termes de performances, il est au même niveau, voire meilleur, que la méthode lexsort:
la source
b = a.view(np.dtype((np.void, a.dtype.itemsize * a.shape[1])))
:?np.void
type de données de la taille du nombre d'octets sur une ligne complète. C'est similaire à ce que vous obtenez si vous avez un tableau denp.uint8
s et que vous le voyez commenp.uint16
s, qui combine toutes les deux colonnes en une seule, mais plus flexible.np.ascontiguousarray
ou similaire pour être généralement sûr (je sais que c'est un peu plus restrictif que nécessaire, mais ...). Les lignes doivent être contiguës pour que la vue fonctionne comme prévu.np.unique
sur un tableau denp.void
retours, une erreur liée au fusionnement n'est pas implémenté pour ce type. Cela fonctionne bien en 1.7.-0.
ne sera pas égal à+0.
, alors qu'une comparaison élément par élément aurait-0.==+0.
(comme spécifié par la norme float ieee). Voir stackoverflow.com/questions/26782038/…Si vous voulez éviter les frais de mémoire liés à la conversion en une série de tuples ou une autre structure de données similaire, vous pouvez exploiter les tableaux structurés de numpy.
L'astuce consiste à afficher votre tableau d'origine comme un tableau structuré où chaque élément correspond à une ligne du tableau d'origine. Cela ne fait pas de copie et est assez efficace.
Comme exemple rapide:
Pour comprendre ce qui se passe, jetez un œil aux résultats intermédiaires.
Une fois que nous considérons les choses comme un tableau structuré, chaque élément du tableau est une ligne de votre tableau d'origine. (Fondamentalement, c'est une structure de données similaire à une liste de tuples.)
Une fois que nous avons exécuté
numpy.unique
, nous récupérons un tableau structuré:Que nous devons ensuite voir comme un tableau "normal" (
_
stocke le résultat du dernier calcul dansipython
, c'est pourquoi vous voyez_.view...
):Et puis remodeler en un tableau 2D (
-1
est un espace réservé qui indique à numpy de calculer le nombre correct de lignes, donnez le nombre de colonnes):Évidemment, si vous vouliez être plus concis, vous pourriez l'écrire comme suit:
Ce qui se traduit par:
la source
lexsort
. Je pensais que vous faisiez référence à l'utilisation d'une liste de tuples. Oui,lexsort
c'est probablement la meilleure option dans ce cas. Je l'avais oublié et je suis passé à une solution trop complexe.np.unique
quand je l'exécutenp.random.random(100).reshape(10,10)
retourne tous les éléments individuels uniques, mais vous voulez les lignes uniques, donc vous devez d'abord les mettre en tuples:C'est la seule façon dont je vous vois changer les types pour faire ce que vous voulez, et je ne suis pas sûr si l'itération de la liste pour changer en tuples est d'accord avec votre "pas de boucle"
la source
< 100
lignes par appel. Cela décrit précisément la façon dont l'exécution sur des lignes uniques est effectuée.uniques
contient des éléments uniques. Potentiellement, je comprends mal la forme attendue dearray
- pourriez-vous être plus précis ici?uniques
est triée (et donc différente des lignes dearray
).B = np.array([[1,2],[2,1]]); A = np.unique([tuple(row) for row in B]); print(A) = array([[1, 2],[1, 2]])
np.unique fonctionne en triant un tableau aplati, puis en vérifiant si chaque élément est égal au précédent. Cela peut être fait manuellement sans aplatir:
Cette méthode n'utilise pas de tuples et devrait être beaucoup plus rapide et plus simple que les autres méthodes présentées ici.
Remarque: une version précédente de cela n'avait pas l'ind juste après un [, ce qui signifie que les mauvais indices ont été utilisés. De plus, Joe Kington souligne que cela fait une variété de copies intermédiaires. La méthode suivante fait moins, en faisant une copie triée puis en utilisant des vues de celle-ci:
C'est plus rapide et utilise moins de mémoire.
En outre, si vous souhaitez rechercher des lignes uniques dans un ndarray quel que soit le nombre de dimensions dans le tableau, les éléments suivants fonctionneront:
Un problème restant intéressant serait si vous vouliez trier / unique le long d'un axe arbitraire d'un tableau de dimensions arbitraires, ce qui serait plus difficile.
Éditer:
Pour démontrer les différences de vitesse, j'ai exécuté quelques tests en ipython des trois méthodes différentes décrites dans les réponses. Avec votre a exact, il n'y a pas trop de différence, bien que cette version soit un peu plus rapide:
Avec un plus grand, cependant, cette version finit par être beaucoup, beaucoup plus rapide:
la source
a[ind[1:]]
une copie, etc.) D'un autre côté, votre solution est généralement 2 à 3 fois plus rapide que la mienne jusqu'à ce que vous soyez à court de RAM.dtype
votre timing? Je pense que vous vous êtes trompé. Sur mon système, appelernp.unique
comme décrit dans ma réponse est légèrement plus rapide que d'utiliser l'une de vos deux versionsnp.lexsort
. Et il est environ 5 fois plus rapide si le tableau pour trouver des uniques a une forme(10000, 100)
. Même si vous décidez de réimplémenter ce qui réduit lenp.unique
temps d'exécution (mineur), le regroupement de chaque ligne en un seul objet exécute des comparaisons plus rapides que d'avoir à faire appelnp.any
à la comparaison des colonnes, en particulier pour les nombres de colonnes plus élevés.dtype
c'est justea.dtype
, c'est-à-dire le type de données consultées, comme l'a fait Joe Kington dans sa réponse. S'il y a beaucoup de colonnes, une autre façon (imparfaite!) De faire avancer les choseslexsort
est de ne trier que sur quelques colonnes. C'est spécifique aux données car il faut savoir quelles colonnes fournissent suffisamment de variance pour trier parfaitement. Par exemple ,a.shape = (60000, 500)
- tri sur les 3 premières colonnes:ind = np.lexsort((a[:, 2], a[:, 1], a[:, 0]))
. Le gain de temps est assez important, mais l'avertissement encore une fois: il pourrait ne pas attraper tous les cas - cela dépend des données.Voici une autre variante de la réponse pythonique @Greg
la source
J'ai comparé l'alternative suggérée pour la vitesse et j'ai découvert que, étonnamment, la
unique
solution de vue nulle est même un peu plus rapide que le natif de numpyunique
avec l'axis
argument. Si vous cherchez de la vitesse, vous voudrezCode pour reproduire l'intrigue:
la source
vstack_dict
:, n'utilise jamais de dict, les accolades sont une compréhension d'ensemble, et donc son comportement est presque identique àvstatck_set
. Depuis, lavstack_dict
ligne de performance est manquante pour le graphique, il semble qu'elle soit simplement couverte par levstack_set
graphique de performance, car ils sont tellement similaires!vstack
variante.Je n'ai aimé aucune de ces réponses, car aucune ne gère les tableaux à virgule flottante dans un sens d'algèbre linéaire ou d'espace vectoriel, où deux lignes étant «égales» signifie «à l'intérieur d'un some». La seule réponse qui a un seuil de tolérance, https://stackoverflow.com/a/26867764/500207 , a pris le seuil pour être à la fois précision élémentaire et décimale , ce qui fonctionne dans certains cas mais n'est pas aussi mathématiquement général qu'un vraie distance vectorielle.
Voici ma version:
La fonction du domaine public ci-dessus utilise
scipy.spatial.distance.pdist
pour trouver la distance euclidienne (personnalisable) entre chaque paire de lignes. Ensuite, il compare chaque distance à unethresh
ancienne pour trouver les lignes qui sont à l'intérieur lesthresh
unes des autres, et renvoie une seule ligne de chaquethresh
cluster.Comme indiqué, la distance
metric
n'a pas besoin d'être euclidienne -pdist
peut calculer diverses distances, y compriscityblock
(norme Manhattan) etcosine
(l'angle entre les vecteurs).Si
thresh=0
(par défaut), les lignes doivent être à peu près exactes pour être considérées comme «uniques». Autres bonnes valeurs pourthresh
une précision machine à l'échelle, c'est-à-direthresh=np.spacing(1)*1e3
.la source
set
) comme représentatif de chaquethresh
quartier de taille, la fonction pourrait permettre à la l'utilisateur pour spécifier comment choisir ce point, par exemple, utiliser la «médiane» ou le point le plus proche du centroïde, etc.thresh
-cluster serait aléatoire en raison de la nature non ordonnée deset
. Bien sûr , c'est un brainfart de ma part, lesset
tuples stocke des index qui sontthresh
-neighborhood, donc celafindRows
fait en retour de fait, pour chaquethresh
-cluster, la première ligne en elle.Pourquoi ne pas utiliser
drop_duplicates
de pandas:la source
Le paquet numpy_indexed (avertissement: je suis son auteur) enveloppe la solution publiée par Jaime dans une interface agréable et testée, ainsi que de nombreuses autres fonctionnalités:
la source
np.unique fonctionne avec une liste de tuples:
Avec une liste de listes, il soulève un
TypeError: unhashable type: 'list'
la source
Sur la base de la réponse de cette page, j'ai écrit une fonction qui reproduit la capacité de la fonction de MATLAB
unique(input,'rows')
, avec la fonctionnalité supplémentaire d'accepter la tolérance pour vérifier l'unicité. Il renvoie également les indices tels quec = data[ia,:]
etdata = c[ic,:]
. Veuillez signaler si vous constatez des écarts ou des erreurs.la source
Au-delà de @Jaime excellente réponse, une autre façon de réduire une ligne consiste à utiliser
a.strides[0]
(en supposant qu'ila
est C-contigu) qui est égal àa.dtype.itemsize*a.shape[0]
. En outrevoid(n)
est un raccourci pourdtype((void,n))
. on arrive enfin à cette version la plus courte:Pour
la source
Pour un usage général comme les tableaux imbriqués multidimensionnels 3D ou supérieurs, essayez ceci:
qui satisfait votre jeu de données 2D:
donne:
Mais aussi des tableaux 3D comme:
donne:
la source
unique
return_index
comme Jaime devraitreturn
simplifier cette dernière ligne. Il suffit d'indexer l'originalar
sur l'axe droit.Aucune de ces réponses n'a fonctionné pour moi. Je suppose que mes lignes uniques contiennent des chaînes et non des nombres. Cependant, cette réponse d'un autre fil a fonctionné:
Source: https://stackoverflow.com/a/38461043/5402386
Vous pouvez utiliser les méthodes de la liste .count () et .index ()
la source
Nous pouvons réellement transformer le tableau numpy numérique mxn en tableau de chaînes numpy mx 1, veuillez essayer d'utiliser la fonction suivante, elle fournit count , inverse_idx et etc, tout comme numpy.unique:
Exemple:
la source
Permet d'obtenir l'intégralité de la matrice numpy sous forme de liste, puis de supprimer les doublons de cette liste, et enfin de renvoyer notre liste unique dans une matrice numpy:
la source
La solution la plus simple consiste à faire des lignes un élément unique en les transformant en chaînes. Chaque ligne peut ensuite être comparée dans son ensemble pour son caractère unique à l'aide de numpy. Cette solution est généralisable, il vous suffit de remodeler et de transposer votre tableau pour d'autres combinaisons. Voici la solution au problème fourni.
Va donner:
Envoyer mon prix Nobel par la poste
la source
la source