733 votes

Sélection par chaîne partielle dans un DataFrame pandas

J'ai un DataFrame avec 4 colonnes dont 2 contiennent des valeurs de type chaîne. Je me demandais s'il existait un moyen de sélectionner des lignes sur la base d'une correspondance partielle de chaînes de caractères dans une colonne particulière ?

En d'autres termes, une fonction ou une fonction lambda qui ferait quelque chose comme

re.search(pattern, cell_in_question) 

renvoyant un booléen. Je connais la syntaxe de df[df['A'] == "hello world"] mais je n'arrive pas à trouver un moyen de faire de même avec une correspondance partielle de chaîne de caractères, par exemple 'hello' .

Quelqu'un pourrait-il m'indiquer la bonne direction ?

22voto

Mike Points 2858

Disons que vous avez les éléments suivants DataFrame :

>>> df = pd.DataFrame([['hello', 'hello world'], ['abcd', 'defg']], columns=['a','b'])
>>> df
       a            b
0  hello  hello world
1   abcd         defg

Vous pouvez toujours utiliser le in dans une expression lambda pour créer votre filtre.

>>> df.apply(lambda x: x['a'] in x['b'], axis=1)
0     True
1    False
dtype: bool

L'astuce ici est d'utiliser le axis=1 dans l'option apply pour passer les éléments à la fonction lambda ligne par ligne, par opposition à colonne par colonne.

0 votes

Comment puis-je modifier ce qui précède pour dire que x['a'] n'existe qu'au début de x['b'] ?

1 votes

L'application est une mauvaise idée en termes de performances et de mémoire. Voir cette réponse .

18voto

cardamom Points 1831

Si vous avez besoin de faire un insensible à la casse recherche d'une chaîne de caractères dans une colonne de dataframe pandas :

df[df['A'].str.contains("hello", case=False)]

14voto

user288925 Points 763

Vous pouvez essayer de les considérer comme des chaînes de caractères :

df[df['A'].astype(str).str.contains("Hello|Britain")]

1 votes

Merci beaucoup, votre réponse m'a beaucoup aidé car j'avais du mal à filtrer un dataframe via une colonne dont les données étaient de type bool. Votre solution m'a permis de réaliser le filtre dont j'avais besoin. +1 pour vous.

9voto

Supposons que nous ayons une colonne nommée "ENTITY" dans le cadre de données. df . Nous pouvons filtrer nos df ,pour avoir la totalité du cadre de données df dans lequel les lignes de la colonne "entité" ne contiennent pas "DM" en utilisant un masque comme suit :

mask = df['ENTITY'].str.contains('DM')

df = df.loc[~(mask)].copy(deep=True)

6voto

euforia Points 161

Voici ce que j'ai fini par faire pour les correspondances partielles de chaînes. Si quelqu'un a une façon plus efficace de le faire, faites-le moi savoir.

def stringSearchColumn_DataFrame(df, colName, regex):
    newdf = DataFrame()
    for idx, record in df[colName].iteritems():

        if re.search(regex, record):
            newdf = concat([df[df[colName] == record], newdf], ignore_index=True)

    return newdf

3 votes

Cela devrait être 2x à 3x plus rapide si vous compilez le regex avant la boucle : regex = re.compile(regex) et ensuite if regex.search(record)

1 votes

@MarkokraM docs.python.org/3.6/library/re.html#re.compile indique que les regex les plus récentes sont mises en cache pour vous, de sorte que vous n'avez pas besoin de compiler vous-même.

0 votes

N'utilisez pas iteritems pour itérer sur un DataFrame. C'est la dernière solution en termes de pandicité et de performances.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X