J'ai une liste et je veux trouver une paire différente dans la liste . J'implémente une fonction -> different ()
import numpy as np
def different(array):
res = []
for (x1, y1), (x2, y2) in array:
if (x1, y1) != (x2, y2):
res.append([(x1, y1), (x2, y2)])
return res
a = np.array([[[1, 2], [3, 4]],
[[1, 2], [1, 2]],
[[7, 9], [6, 3]],
[[3, 3], [3, 3]]])
out = different(a) # get [[(1, 2), (3, 4)],
# [(7, 9), (6, 3)]]
Existe-t-il une autre façon de procéder? Je souhaite améliorer ma fonction différent .. La taille de la liste peut être supérieure à 100 000.
La façon numpy de le faire est
import numpy as np
a = np.array([[[1, 2], [3, 4]],
[[1, 2], [1, 2]],
[[7, 9], [6, 3]],
[[3, 3], [3, 3]]])
b = np.logical_or(a[:,0,0] != a[:,1,0], a[:,0,1] != a[:,1,1])
print(a[b])
a[~(a[:, 0] == a[:, 1]).all(1)]
array([[[1, 2],
[3, 4]],
[[7, 9],
[6, 3]]])
Cela fonctionne en prenant la première paire de chaque sous-tableau et en comparant chaque avec la deuxième paire. Tous les sous-tableaux pour lesquels des entrées non identiques seulement sont sélectionnées. Considérer,
a[:, 0] == a[:, 1]
array([[False, False],
[ True, True],
[False, False],
[ True, True]])
A partir de là, nous voulons les lignes qui n'ont pas True à chaque colonne. Donc, sur ce résultat, utilisez all
, puis annulez le résultat.
~(a[:, 0] == a[:, 1]).all(1)
array([ True, False, True, False])
Cela vous donne un masque que vous pouvez ensuite utiliser pour sélectionner les sous-matrices de a
.
np.logical_or.reduce
Semblable à la première option ci-dessus, mais aborde ce problème de l'autre côté (voir la loi de DeMorgan).
a[np.logical_or.reduce(a[:, 0] != a[:, 1], axis=1)]
Lorsqu'il existe autant d'approches différentes d'un problème, des comparaisons de temps peuvent vraiment aider à identifier les meilleures réponses.
Nous utilisons un tableau de taille (200000, 2, 2)
sous la forme OP Vincentlai a souligné que sa taille est dans la plage de la taille attendue du tableau.
a = np.array(np.random.randint(10, size=(200000, 2, 2)))
numpy.logical_and
%timeit b = a[np.logical_and(a[:,0,0] != a[:,1,0], a[:,0,1] != a[:,1,1])]
>>> 5.12 ms ± 110 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit b = a[~(a[:, 0] == a[:, 1]).all(1)]
>>> 13.7 ms ± 559 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
numpy.logical_or
%timeit b = a[np.logical_or.reduce(a[:, 0] != a[:, 1], axis=1)]
>>> 13.2 ms ± 498 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit b = list(filter(lambda x: x[0]!=x[1],a.tolist()))
>>> 102 ms ± 4.02 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit b = [[(x1, y1), (x2, y2)] for (x1, y1), (x2, y2) in a if (x1, y1) != (x2, y2)]
>>> 752 ms ± 11.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
L'approche de Joe avec numpy.logical_and
est de loin la plus rapide. Comme on pouvait s'y attendre, chaque approche complète en python est extrêmement courte.
En utilisant la compréhension de liste sur une ligne, on peut faire comme ci-dessous,
items_list = [[[1, 2], [3, 4]],
[[1, 2], [1, 2]],
[[7, 9], [6, 3]],
[[3, 3], [3, 3]]
]
# Output
[itm for itm in items_list if itm[0] != itm[1]]
Essayez d’utiliserfilter
:
import numpy as np
def different(array):
return list(filter(lambda x: x[0]!=x[1],array.tolist()))
a = np.array([[[1, 2], [3, 4]],
[[1, 2], [1, 2]],
[[7, 9], [6, 3]],
[[3, 3], [3, 3]]])
out = different(a)
print(out)
Utiliser une liste de compréhension
def different(array):
return [[(x1, y1), (x2, y2)] for (x1, y1), (x2, y2) in array if (x1, y1) != (x2, y2)]