Comment déterminer si une colonne Pandas contient une valeur particulière


157

J'essaie de déterminer s'il y a une entrée dans une colonne Pandas qui a une valeur particulière. J'ai essayé de faire ça avec if x in df['id']. Je pensais que cela fonctionnait, sauf lorsque je lui ai donné une valeur dont je savais qu'elle ne figurait pas dans la colonne, 43 in df['id']elle retournait toujours True. Lorsque je sous-ensemble à une trame de données contenant uniquement des entrées correspondant à l'identifiant manquant, df[df['id'] == 43]il n'y a, évidemment, aucune entrée. Comment déterminer si une colonne dans un bloc de données Pandas contient une valeur particulière et pourquoi ma méthode actuelle ne fonctionne-t-elle pas? (Pour info, j'ai le même problème lorsque j'utilise l'implémentation dans cette réponse à une question similaire).

Réponses:


183

in of a Series vérifie si la valeur est dans l'index:

In [11]: s = pd.Series(list('abc'))

In [12]: s
Out[12]: 
0    a
1    b
2    c
dtype: object

In [13]: 1 in s
Out[13]: True

In [14]: 'a' in s
Out[14]: False

Une option consiste à voir s'il s'agit de valeurs uniques :

In [21]: s.unique()
Out[21]: array(['a', 'b', 'c'], dtype=object)

In [22]: 'a' in s.unique()
Out[22]: True

ou un ensemble python:

In [23]: set(s)
Out[23]: {'a', 'b', 'c'}

In [24]: 'a' in set(s)
Out[24]: True

Comme indiqué par @DSM, il peut être plus efficace (surtout si vous ne faites cela que pour une valeur) de simplement utiliser directement sur les valeurs:

In [31]: s.values
Out[31]: array(['a', 'b', 'c'], dtype=object)

In [32]: 'a' in s.values
Out[32]: True

2
Je ne veux pas savoir si c'est nécessairement unique, je veux surtout savoir si c'est là.
Michael

24
Je pense que 'a' in s.valuesdevrait être plus rapide pour les longues séries.
DSM

4
@AndyHayden Savez-vous pourquoi, car 'a' in s, les pandas choisissent de vérifier l'index plutôt que les valeurs de la série? Dans les dictionnaires, ils vérifient les clés, mais une série de pandas devrait se comporter davantage comme une liste ou un tableau, non?
Lei

3
À partir de pandas 0.24.0, en utilisant s.valueset df.valuesest fortement déconseillé. Regarde ça . En outre, il s.valuesest en fait beaucoup plus lent dans certains cas.
Qusai Alothman

1
@QusaiAlothman non plus .to_numpyou .arraysont disponibles sur une série, donc je ne suis pas entièrement sûr de l'alternative qu'ils préconisent (je ne lis pas "fortement découragé"). En fait, ils disent que .values ​​peut ne pas renvoyer un tableau numpy, par exemple dans le cas d'un catégorique ... mais c'est très bien car incela fonctionnera toujours comme prévu (en fait plus efficacement que son homologue de tableau numpy)
Andy Hayden

27

Vous pouvez également utiliser pandas.Series.isin bien qu'il soit un peu plus long que 'a' in s.values:

In [2]: s = pd.Series(list('abc'))

In [3]: s
Out[3]: 
0    a
1    b
2    c
dtype: object

In [3]: s.isin(['a'])
Out[3]: 
0    True
1    False
2    False
dtype: bool

In [4]: s[s.isin(['a'])].empty
Out[4]: False

In [5]: s[s.isin(['z'])].empty
Out[5]: True

Mais cette approche peut être plus flexible si vous devez faire correspondre plusieurs valeurs à la fois pour un DataFrame (voir DataFrame.isin )

>>> df = DataFrame({'A': [1, 2, 3], 'B': [1, 4, 7]})
>>> df.isin({'A': [1, 3], 'B': [4, 7, 12]})
       A      B
0   True  False  # Note that B didn't match 1 here.
1  False   True
2   True   True

1
Vous pouvez également utiliser la fonction DataFrame.any () :s.isin(['a']).any()
merci le

17
found = df[df['Column'].str.contains('Text_to_search')]
print(found.count())

le found.count()testament contient le nombre de correspondances

Et s'il vaut 0, cela signifie que la chaîne n'a pas été trouvée dans la colonne.


2
a travaillé pour moi, mais j'ai utilisé len (trouvé) pour obtenir le décompte
kztd

1
Oui, len (trouvé) est une meilleure option.
Shahir Ansari

1
Cette approche a fonctionné pour moi mais j'ai dû inclure les paramètres na=Falseet regex=Falsepour mon cas d'utilisation, comme expliqué ici: pandas.pydata.org/pandas-docs/stable/reference/api/…
Mabyn

1
Mais string.contains effectue une recherche de sous-chaînes. Ex: Si une valeur appelée "head_hunter" est présente. Passer "head" dans str.c contient des correspondances et donne True, ce qui est faux.
karthikeyan

@karthikeyan Ce n'est pas faux. Dépend du contexte de votre recherche. Que faire si vous recherchez des adresses ou des produits. Vous aurez besoin de tous les produits qui correspondent à la description.
Shahir Ansari le

6

J'ai fait quelques tests simples:

In [10]: x = pd.Series(range(1000000))

In [13]: timeit 999999 in x.values
567 µs ± 25.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [15]: timeit x.isin([999999]).any()
9.54 ms ± 291 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [16]: timeit (x == 999999).any()
6.86 ms ± 107 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [17]: timeit 999999 in set(x)
79.8 ms ± 1.98 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [21]: timeit x.eq(999999).any()
7.03 ms ± 33.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [22]: timeit x.eq(9).any()
7.04 ms ± 60 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [24]: timeit 9 in x.values
666 µs ± 15.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Fait intéressant, peu importe si vous recherchez 9 ou 999999, il semble que cela prenne à peu près le même temps en utilisant la syntaxe in (doit utiliser la recherche binaire)

In [24]: timeit 9 in x.values
666 µs ± 15.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [25]: timeit 9999 in x.values
647 µs ± 5.21 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [26]: timeit 999999 in x.values
642 µs ± 2.11 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [27]: timeit 99199 in x.values
644 µs ± 5.31 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [28]: timeit 1 in x.values
667 µs ± 20.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

On dirait que l'utilisation de x.values ​​est la plus rapide, mais peut-être y a-t-il une manière plus élégante dans les pandas?


Ce serait formidable si vous modifiez l'ordre des résultats du plus petit au plus grand. Bon travail!
smm

4

Ou utilisez Series.tolistou Series.any:

>>> s = pd.Series(list('abc'))
>>> s
0    a
1    b
2    c
dtype: object
>>> 'a' in s.tolist()
True
>>> (s=='a').any()
True

Series.tolistfait une liste de a Series, et de l'autre je reçois juste un booléen Seriesd'un régulier Series, puis vérifie s'il y a des Trues dans le booléen Series.


1

Condition simple:

if any(str(elem) in ['a','b'] for elem in df['column'].tolist()):

1

Utilisation

df[df['id']==x].index.tolist()

Si xest présent, idil retournera la liste des index où il est présent, sinon il donnera une liste vide.



0

Supposons que votre dataframe ressemble à:

entrez la description de l'image ici

Vous voulez maintenant vérifier si le nom de fichier "80900026941984" est présent ou non dans le dataframe.

Vous pouvez simplement écrire:

if sum(df["filename"].astype("str").str.contains("80900026941984")) > 0:
    print("found")
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.