web-dev-qa-db-fra.com

NumPy: comparaison d'éléments dans deux tableaux

Quelqu'un a-t-il déjà abordé ce problème? Disons que vous avez deux tableaux comme celui-ci

a = array([1,2,3,4,5,6])
b = array([1,4,5])

Existe-t-il un moyen de comparer les éléments d’un élément existant dans b? Par exemple,

c = a == b # Wishful example here
print c
array([1,4,5])
# Or even better
array([True, False, False, True, True, False])

J'essaie d'éviter les boucles, car cela prendrait des siècles avec des millions d'éléments. Des idées? 

À votre santé

37
ebressert

En fait, il existe une solution encore plus simple que celles-ci:

import numpy as np

a = array([1,2,3,4,5,6])
b = array([1,4,5])

c = np.in1d(a,b)

Le c résultant est alors:

array([ True, False, False,  True,  True, False], dtype=bool)
49
eteq

Utilisez np.intersect1d. 

#!/usr/bin/env python
import numpy as np
a = np.array([1,2,3,4,5,6])
b = np.array([1,4,5])
c=np.intersect1d(a,b)
print(c)
# [1 4 5]

Notez que np.intersect1d donne la mauvaise réponse si a ou b ont des éléments non uniques. Dans ce cas, utilisez Np.intersect1d_nu.

Il existe également np.setdiff1d, setxor1d, setmember1d et union1d. Voir Numpy Example List With Doc

18
unutbu

Numpy a une fonction set numpy.setmember1d () qui fonctionne sur les tableaux triés et uniques et renvoie exactement le tableau booléen souhaité. Si les tableaux d'entrée ne correspondent pas aux critères, vous devez convertir le format défini et inverser la transformation sur le résultat.

import numpy as np
a = np.array([6,1,2,3,4,5,6])
b = np.array([1,4,5])

# convert to the uniqued form
a_set, a_inv = np.unique1d(a, return_inverse=True)
b_set = np.unique1d(b)
# calculate matching elements
matches = np.setmea_set, b_set)
# invert the transformation
result = matches[a_inv]
print(result)
# [False  True False False  True  True False]

Edit: Malheureusement, la méthode setmember1d de numpy est vraiment inefficace. La méthode de recherche triée et affectée que vous proposez fonctionne plus rapidement, mais si vous pouvez attribuer directement, vous pouvez également affecter directement le résultat et éviter de nombreuses copies inutiles. De plus, votre méthode échouera si b contient quelque chose qui ne soit pas dans a. Ce qui suit corrige ces erreurs:

result = np.zeros(a.shape, dtype=np.bool)
idxs = a.searchsorted(b)
idxs = idxs[np.where(idxs < a.shape[0])] # Filter out out of range values
idxs = idxs[np.where(a[idxs] == b)] # Filter out where there isn't an actual match
result[idxs] = True
print(result)

Mes repères montrent cela à 91us vs. 6.6ms pour votre approche et 109ms pour numpy setmember1d sur 1M élément a et 100 élément b.

2
Ants Aasma

Merci pour votre réponse kaizer.se. Ce n'est pas tout à fait ce que je cherchais, mais avec une suggestion d'un ami et ce que vous avez dit, j'ai proposé ce qui suit. 

import numpy as np

a = np.array([1,4,5]).astype(np.float32)
b = np.arange(10).astype(np.float32)

# Assigning matching values from a in b as np.nan
b[b.searchsorted(a)] = np.nan

# Now generating Boolean arrays
match = np.isnan(b)
nonmatch = match == False

C'est un processus un peu fastidieux, mais il bat plus que les boucles d'écriture ou le tissage avec des boucles. 

À votre santé

2
ebressert

ebresset, votre réponse ne fonctionnera que si a est un sous-ensemble de b (et a et b sont triés). Sinon, la recherche triée retournera de faux index. Je devais faire quelque chose de similaire et le combiner avec votre code:

# Assume a and b are sorted
idxs = numpy.mod(b.searchsorted(a),len(b))
idxs = idxs[b[idxs]==a]
b[idxs] = numpy.nan
match = numpy.isnan(b)
0
AFoglia