web-dev-qa-db-fra.com

Comment tester si une chaîne contient l'une des sous-chaînes d'une liste, dans des pandas?

Existe-t-il une fonction qui serait l’équivalent d’une combinaison de df.isin() et df[col].str.contains()?

Par exemple, disons que j’ai la série s = pd.Series(['cat','hat','dog','fog','pet']) et que je veux trouver tous les endroits où s contient l’un quelconque des ['og', 'at'], Je voudrais tout avoir sauf 'animal'.

J'ai une solution, mais c'est plutôt inélégant:

searchfor = ['og', 'at']
found = [s.str.contains(x) for x in searchfor]
result = pd.DataFrame[found]
result.any()

Y a-t-il une meilleure manière de faire cela?

75
ari

Une option consiste simplement à utiliser la regex | caractère pour essayer de faire correspondre chacune des sous-chaînes des mots de votre série s (toujours en utilisant str.contains).

Vous pouvez construire l’expression rationnelle en joignant les mots dans searchfor avec |:

>>> searchfor = ['og', 'at']
>>> s[s.str.contains('|'.join(searchfor))]
0    cat
1    hat
2    dog
3    fog
dtype: object

Comme @AndyHayden l'a noté dans les commentaires ci-dessous, faites attention si vos sous-chaînes ont des caractères spéciaux tels que $ et ^ que vous voulez assortir littéralement. Ces caractères ont des significations spécifiques dans le contexte des expressions régulières et affecteront la correspondance.

Vous pouvez sécuriser votre liste de sous-chaînes en échappant des caractères non alphanumériques avec re.escape:

>>> import re
>>> matches = ['$money', 'x^y']
>>> safe_matches = [re.escape(m) for m in matches]
>>> safe_matches
['\\$money', 'x\\^y']

Les chaînes figurant dans cette nouvelle liste correspondront littéralement à chaque caractère lorsqu’elles sont utilisées avec str.contains.

146
Alex Riley

Vous pouvez utiliser str.contains Seul avec un motif regex utilisant OR (|):

s[s.str.contains('og|at')]

Ou vous pouvez ajouter la série à un dataframe puis utiliser str.contains:

df = pd.DataFrame(s)
df[s.str.contains('og|at')] 

Sortie:

0 cat
1 hat
2 dog
3 fog 
33
l'L'l