Cómo determinar si una columna Pandas contiene un valor particular

156

Estoy tratando de determinar si hay una entrada en una columna Pandas que tenga un valor particular. Traté de hacer esto con if x in df['id']. Pensé que esto estaba funcionando, excepto cuando le di un valor que sabía que no estaba en la columna 43 in df['id']que aún devolvía True. Cuando subconjunto a un marco de datos que solo contiene entradas que coinciden con la identificación faltante df[df['id'] == 43], obviamente, no hay entradas en él. ¿Cómo puedo determinar si una columna en un marco de datos de Pandas contiene un valor particular y por qué mi método actual no funciona? (Para su información, tengo el mismo problema cuando uso la implementación en esta respuesta a una pregunta similar).

Miguel
fuente

Respuestas:

183

in de una serie comprueba si el valor está en el índice:

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

Una opción es ver si está en valores únicos :

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

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

o un conjunto de python:

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

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

Como señaló @DSM, puede ser más eficiente (especialmente si solo está haciendo esto por un valor) usar directamente en los valores:

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

In [32]: 'a' in s.values
Out[32]: True
Andy Hayden
fuente
2
No quiero saber si es necesariamente único, principalmente quiero saber si está allí.
Michael
24
Creo que 'a' in s.valuesdebería ser más rápido para series largas.
DSM
44
@AndyHayden ¿Sabes por qué, para 'a' in s, los pandas eligen verificar el índice en lugar de los valores de la serie? En los diccionarios verifican las claves, pero una serie de pandas debería comportarse más como una lista o matriz, ¿no?
Lei
3
A partir de pandas 0.24.0, usando s.valuesy df.valuesestá altamente desacreditado. Mira esto . Además, en s.valuesrealidad es mucho más lento en algunos casos.
Qusai Alothman
1
@QusaiAlothman ni .to_numpyo .arrayestán disponibles en una serie, así que no estoy totalmente seguro de lo que están abogando alternativa (no leo "muy desanimados"). De hecho, dicen que .valores pueden no devolver una matriz numpy, por ejemplo, en el caso de una categórica ... pero está bien, ya inque funcionará como se esperaba (de hecho, más eficientemente que su contraparte de matriz numpy)
Andy Hayden
27

También puedes usar pandas.Series.isin aunque es un poco más largo 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

Pero este enfoque puede ser más flexible si necesita hacer coincidir varios valores a la vez para un DataFrame (consulte 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
fiesta
fuente
También puede usar la función DataFrame.any () :s.isin(['a']).any()
thando
17
found = df[df['Column'].str.contains('Text_to_search')]
print(found.count())

el found.count()testamento contiene varias coincidencias

Y si es 0, significa que no se encontró una cadena en la columna.

Shahir Ansari
fuente
2
funcionó para mí, pero usé len (encontrado) para obtener el recuento
kztd
1
Sí, len (encontrado) es una opción algo mejor.
Shahir Ansari
1
Este enfoque funcionó para mí, pero tuve que incluir los parámetros na=Falsey regex=Falsepara mi caso de uso, como se explica aquí: pandas.pydata.org/pandas-docs/stable/reference/api/…
Mabyn
1
Pero string.contains realiza una búsqueda de subcadenas. Ej: si hay un valor llamado "head_hunter". Pasar "cabeza" en str.contiene coincidencias y le da a True que está mal
karthikeyan
@karthikeyan No está mal. Depende del contexto de su búsqueda. ¿Qué sucede si busca direcciones o productos? Necesitará todos los productos que se ajusten a la descripción.
Shahir Ansari
6

Hice algunas pruebas 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)

Curiosamente, no importa si buscas 9 o 999999, parece que lleva la misma cantidad de tiempo usar la sintaxis in (debe estar usando la búsqueda binaria)

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)

Parece que usar x.values ​​es el más rápido, pero ¿tal vez hay una forma más elegante en los pandas?

Allen Wang
fuente
Sería genial si cambia el orden de resultados de menor a mayor. ¡Buen trabajo!
smm
4

O use Series.tolisto 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.tolisthace una lista de a Series, y en el otro solo estoy obteniendo un booleano Seriesde un regular Series, luego verificando si hay alguna Trues en el booleano Series.

U10-Adelante
fuente
1

Condición simple:

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

Utilizar

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

Si xestá presente id, devolverá la lista de índices donde está presente, de lo contrario, dará una lista vacía.

Ramana Sriwidya
fuente
0

Supongamos que su marco de datos se ve así:

ingrese la descripción de la imagen aquí

Ahora desea verificar si el nombre de archivo "80900026941984" está presente en el marco de datos o no.

Simplemente puedes escribir:

if sum(df["filename"].astype("str").str.contains("80900026941984")) > 0:
    print("found")
Namrata Tolani
fuente