web-dev-qa-db-fra.com

Trouver des entrées contenant une sous-chaîne dans un tableau numpy?

J'ai essayé de trouver des entrées dans un tableau contenant une sous-chaîne avec np.where et une condition in:

import numpy as np
foo = "aa"
bar = np.array(["aaa", "aab", "aca"])
np.where(foo in bar)

cela ne retourne qu'un tableau vide.
Pourquoi est-ce si?
Et existe-t-il une bonne solution alternative?

6
SiOx

Nous pouvons utiliser np.core.defchararray.find pour trouver la position de la chaîne foo dans chaque élément de bar, ce qui retournerait -1 s'il n'est pas trouvé. Ainsi, il pourrait être utilisé pour détecter si foo est présent ou non dans chaque élément en vérifiant la présence de -1 dans la sortie de find. Enfin, nous utiliserions np.flatnonzero pour obtenir les index des correspondances. Donc, nous aurions une implémentation, comme si -

np.flatnonzero(np.core.defchararray.find(bar,foo)!=-1)

Exemple de cycle -

In [91]: bar
Out[91]: 
array(['aaa', 'aab', 'aca'], 
      dtype='|S3')

In [92]: foo
Out[92]: 'aa'

In [93]: np.flatnonzero(np.core.defchararray.find(bar,foo)!=-1)
Out[93]: array([0, 1])

In [94]: bar[2] = 'jaa'

In [95]: np.flatnonzero(np.core.defchararray.find(bar,foo)!=-1)
Out[95]: array([0, 1, 2])
9
Divakar

Vous pouvez aussi faire quelque chose comme ça:

mask = [foo in x for x in bar]  
filter = bar[ np.where( mask * bar != '') ]
1
htran

La façon dont vous essayez d'utiliser np.where est incorrecte. Le premier argument de np.where devrait être un tableau booléen, et vous le transmettez simplement à un booléen.

foo in bar
>>> False
np.where(False)
>>> (array([], dtype=int32),)
np.where(np.array([True, True, False]))
>>> (array([0, 1], dtype=int32),)

Le problème est que numpy ne définit pas l'opérateur in comme une opération booléenne élément-wise .

Une façon dont vous pouvez accomplir ce que vous voulez est avec une compréhension de liste.

foo = 'aa'
bar = np.array(['aaa', 'aab', 'aca'])
out = [i for i, v in enumerate(bar) if foo in v]
# out = [0, 1]

bar = ['aca', 'bba', 'baa', 'aaf', 'ccc']
out = [i for i, v in enumerate(bar) if foo in v]
# out = [2, 3]
0
Chris Mueller

Regardez quelques exemples d'utilisation de in:

In [19]: bar = np.array(["aaa", "aab", "aca"])

In [20]: 'aa' in bar
Out[20]: False

In [21]: 'aaa' in bar
Out[21]: True

In [22]: 'aab' in bar
Out[22]: True

In [23]: 'aab' in list(bar) 

Cela ressemble à in lorsqu'il est utilisé avec un tableau fonctionne comme si le tableau était une liste. ndarray a une méthode __contains__, donc in fonctionne, mais c'est probablement simple.

Mais dans tous les cas, notez que in alist ne vérifie pas les sous-chaînes. La strings__contains__ effectue le test de la sous-chaîne, mais je ne connais aucune classe intégrée qui propage le test jusqu'aux chaînes du composant.

Comme Divakar montre qu'il existe une collection de fonctions numpy qui applique des méthodes de chaîne à des éléments individuels d'un tableau.

In [42]: np.char.find(bar, 'aa')
Out[42]: array([ 0,  0, -1])

Docstring:
Ce module contient un ensemble de fonctions pour les opérations et méthodes de chaîne vectorisée. L'alias préféré pour defchararray est numpy.char.

Pour des opérations comme celle-ci, je pense que les vitesses de np.char sont à peu près les mêmes qu'avec:

In [49]: np.frompyfunc(lambda x: x.find('aa'), 1, 1)(bar)
Out[49]: array([0, 0, -1], dtype=object)

In [50]: np.frompyfunc(lambda x: 'aa' in x, 1, 1)(bar)
Out[50]: array([True, True, False], dtype=object)

D'autres tests suggèrent que la ndarray__contains__ opère sur la version flat du tableau, c'est-à-dire que la forme n'affecte pas son comportement.

0
hpaulj