J'ai un DataFrame
avec 4 colonnes dont 2 contiennent des valeurs de chaîne. Je me demandais s'il y avait un moyen de sélectionner des lignes sur la base d'une correspondance de chaîne partielle contre 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 bien la syntaxe de df[df['A'] == "hello world"]
mais je n'arrive pas à trouver un moyen de faire de même avec une correspondance de chaîne partielle 'hello'
.
Quelqu'un pourrait-il m'orienter dans la bonne direction?
df[df['A'].str.contains("Hello|Britain")]
.str.contains
pour utiliser l'.query()
API ?df[df['value'].astype(str).str.contains('1234.+')]
pour filtrer les colonnes non de type chaîne.J'ai essayé la solution proposée ci-dessus:
et a obtenu une erreur:
vous pouvez transformer les valeurs NA en
False
, comme ceci:la source
df[df['A'].astype(str).str.contains("Hello|Britain")]
a aussi bien fonctionnéCe message est destiné aux lecteurs qui souhaitent
isin
)... et j'aimerais en savoir plus sur les méthodes à privilégier par rapport aux autres.
(PS: j'ai vu beaucoup de questions sur des sujets similaires, je pensais que ce serait bien de laisser ça ici.)
Recherche de base de sous-chaîne
str.contains
peut être utilisé pour effectuer des recherches de sous-chaîne ou des recherches basées sur des expressions rationnelles. La recherche par défaut est basée sur une expression rationnelle, sauf si vous la désactivez explicitement.Voici un exemple de recherche basée sur des expressions rationnelles,
Parfois, la recherche d'expression régulière n'est pas requise, alors spécifiez-la
regex=False
pour la désactiver.En termes de performances, la recherche d'expression régulière est plus lente que la recherche de sous-chaîne:
Évitez d'utiliser la recherche basée sur les expressions rationnelles si vous n'en avez pas besoin.
Adressage
ValueError
sParfois, effectuer une recherche de sous-chaîne et filtrer le résultat entraînera
Cela est généralement dû à des données mixtes ou NaN dans votre colonne objet,
Tout ce qui n'est pas une chaîne ne peut pas avoir de méthodes de chaîne appliquées, donc le résultat est NaN (naturellement). Dans ce cas, spécifiez
na=False
d'ignorer les données non-chaîne,Recherche de sous-chaînes multiples
Ceci est plus facilement réalisé grâce à une recherche d'expressions rationnelles à l'aide du tuyau OU d'expression régulière.
Vous pouvez également créer une liste de termes, puis les rejoindre:
Parfois, il est sage d'échapper à vos termes s'ils contiennent des caractères pouvant être interprétés comme des métacaractères d'expression régulière . Si vos termes contiennent l'un des caractères suivants ...
Ensuite, vous devrez utiliser
re.escape
pour les échapper :re.escape
a pour effet d'échapper les caractères spéciaux afin qu'ils soient traités littéralement.Correspondance de mot (s) entier (s)
Par défaut, la recherche de sous-chaîne recherche la sous-chaîne / le modèle spécifié, qu'il s'agisse d'un mot complet ou non. Pour ne faire correspondre que des mots entiers, nous devrons utiliser des expressions régulières ici - en particulier, notre modèle devra spécifier des limites de mots (
\b
).Par exemple,
Considérez maintenant,
contre
Recherche de mots entiers multiples
Similaire à ce qui précède, sauf que nous ajoutons un mot limite (
\b
) au motif joint.Où
p
ressemble à ça,Une excellente alternative: utilisez les listes de compréhension !
Parce que vous pouvez! Et tu devrais! Elles sont généralement un peu plus rapides que les méthodes de chaîne, car les méthodes de chaîne sont difficiles à vectoriser et ont généralement des implémentations en boucle.
Au lieu de,
Utilisez l'
in
opérateur dans une liste de composition,Au lieu de,
Utilisez
re.compile
(pour mettre en cache votre regex) + à l'Pattern.search
intérieur d'une liste de composition,Si "col" a NaN, alors au lieu de
Utilisation,
Plus d' options pour la correspondance partielle de chaîne:
np.char.find
,np.vectorize
,DataFrame.query
.En plus des
str.contains
listes et des listes, vous pouvez également utiliser les alternatives suivantes.np.char.find
Prend en charge les recherches de sous-chaîne (lecture: aucune expression régulière) uniquement.
np.vectorize
Il s'agit d'un wrapper autour d'une boucle, mais avec une charge moindre que la plupart des
str
méthodes pandas .Solutions Regex possibles:
DataFrame.query
Prend en charge les méthodes de chaîne via le moteur python. Cela n'offre aucun avantage visible en termes de performances, mais est néanmoins utile pour savoir si vous devez générer dynamiquement vos requêtes.
Plus d'informations sur
query
et sur laeval
famille de méthodes peuvent être trouvées sur Dynamic Expression Evaluation in pandas en utilisant pd.eval () .Priorité d'utilisation recommandée
str.contains
, pour sa simplicité et sa facilité de gestion des NaN et des données mixtesnp.vectorize
df.query
la source
any(needle in haystack for needling in ['foo', 'bar'] and haystack in (df['col'], df['col2']))
et les variantes que j'ai essayées sont toutes étranglées (ça se plaintany()
et à juste titre donc ... Mais le doc n'est pas du tout clair sur la façon de faire une telle requête.df[['col1', 'col2']].apply(lambda x: x.str.contains('foo|bar')).any(axis=1)
Si quelqu'un se demande comment effectuer un problème connexe: "Sélectionner la colonne par chaîne partielle"
Utilisation:
Et pour sélectionner des lignes par correspondance de chaîne partielle, passez
axis=0
au filtre:la source
df.loc[:, df.columns.str.contains('a')]
df.filter(like='a')
Remarque rapide: si vous souhaitez effectuer une sélection basée sur une chaîne partielle contenue dans l'index, essayez ce qui suit:
la source
Disons que vous disposez des éléments suivants
DataFrame
:Vous pouvez toujours utiliser l'
in
opérateur dans une expression lambda pour créer votre filtre.L'astuce consiste à utiliser l'
axis=1
option dans leapply
pour passer des éléments à la fonction lambda ligne par ligne, par opposition à colonne par colonne.la source
Voici ce que j'ai fini par faire pour les correspondances de chaînes partielles. Si quelqu'un a un moyen plus efficace de le faire, veuillez me le faire savoir.
la source
L'utilisation de contient n'a pas bien fonctionné pour ma chaîne avec des caractères spéciaux. Mais ça a marché.
la source
Si vous devez effectuer une recherche insensible à la casse pour une chaîne dans une colonne de trame de données pandas:
la source
Il y a des réponses avant cela qui accomplissent la fonctionnalité demandée, de toute façon je voudrais montrer la manière la plus générale:
De cette façon, vous obtenez la colonne que vous recherchez, quelle que soit la façon dont elle est écrite.
(Évidemment, vous devez écrire l'expression regex appropriée pour chaque cas)
la source
Peut-être que vous souhaitez rechercher du texte dans toutes les colonnes de la trame de données Pandas, et pas seulement dans leur sous-ensemble. Dans ce cas, le code suivant vous aidera.
Attention. Cette méthode est relativement lente, bien que pratique.
la source