Como determinar se uma coluna do Pandas contém um valor específico

156

Estou tentando determinar se há uma entrada em uma coluna do Pandas que tenha um valor específico. Eu tentei fazer isso com if x in df['id']. Eu pensei que isso estava funcionando, exceto quando eu o alimentei com um valor que eu sabia que não estava na coluna 43 in df['id']que ainda retornava True. Quando subconjunto um quadro de dados contendo apenas entradas correspondentes ao ID ausente df[df['id'] == 43], obviamente não há entradas nele. Como determinar se uma coluna em um quadro de dados do Pandas contém um valor específico e por que meu método atual não funciona? (Para sua informação, eu tenho o mesmo problema quando uso a implementação nesta resposta para uma pergunta semelhante).

Michael
fonte

Respostas:

183

in of a Series verifica se o valor está no í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

Uma opção é verificar se está em valores únicos :

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

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

ou um conjunto de python:

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

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

Conforme apontado pelo @DSM, pode ser mais eficiente (principalmente se você estiver fazendo isso por um valor) usar apenas diretamente os valores:

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

In [32]: 'a' in s.values
Out[32]: True
Andy Hayden
fonte
2
Não quero saber se é necessariamente único, principalmente quero saber se está lá.
Michael Michael
24
Eu acho que 'a' in s.valuesdeveria ser mais rápido para séries longas.
DSM
4
@AndyHayden Você sabe por que, para 'a' in s, os pandas optam por verificar o índice em vez dos valores da série? Nos dicionários, eles checam as chaves, mas uma série de pandas deve se comportar mais como uma lista ou matriz, não?
Lei
3
A partir do pandas 0.24.0, usando s.valuese df.valuesé altamente desaconselhado. Veja isso . Além disso, s.valuesé realmente muito mais lento em alguns casos.
Qusai Alothman 01/02/19
1
@QusaiAlothman nem .to_numpyou .arrayestão disponíveis em uma série, então eu não sou inteiramente certo que alternativa que eles estão defendendo (eu não leio "altamente desencorajada"). Na verdade, eles estão dizendo que .values ​​podem não retornar uma matriz numpy, por exemplo, no caso de uma categoria categórica ... mas tudo bem, pois inainda funcionará conforme o esperado (na verdade, mais eficientemente que sua equivalente numpy)
Andy Hayden
27

Você também pode usar o pandas.Series.isin, embora seja um pouco mais longo 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

Mas essa abordagem pode ser mais flexível se você precisar corresponder vários valores de uma vez para um 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
festa
fonte
Você também pode usar a função DataFrame.any () :s.isin(['a']).any()
thando
17
found = df[df['Column'].str.contains('Text_to_search')]
print(found.count())

o found.count()testamento contém o número de correspondências

E se for 0, significa que a string não foi encontrada na coluna.

Shahir Ansari
fonte
2
trabalhou para mim, mas eu usei len (encontrada) para obter a contagem
kztd
1
Sim, len (encontrado) é uma opção um pouco melhor.
Shahir Ansari
1
Essa abordagem funcionou para mim, mas eu tive que incluir os parâmetros na=Falsee regex=Falsepara o meu caso de uso, conforme explicado aqui: pandas.pydata.org/pandas-docs/stable/reference/api/…
Mabyn
1
Mas string.contains faz uma pesquisa de substring. Ex: Se um valor chamado "head_hunter" estiver presente. Passar "head" em str. contém correspondências e dá True que está errado.
karthikeyan
@karthikeyan Não está errado. Depende do contexto da sua pesquisa. E se você estiver procurando endereços ou produtos. Você precisará de todos os produtos adequados à descrição.
Shahir Ansari
6

Eu fiz alguns testes 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, não importa se você consulta 9 ou 999999, parece que leva a mesma quantidade de tempo usando a sintaxe in (deve estar usando a pesquisa binária)

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 ​​é o mais rápido, mas talvez exista uma maneira mais elegante em pandas?

Allen Wang
fonte
Seria ótimo se você alterasse a ordem dos resultados do menor para o maior. Bom trabalho!
smm 10/01
4

Ou use 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.tolistfaz uma lista sobre a Series, e a outra, estou apenas obtendo um booleano Seriesde um regular e Series, em seguida, verificando se há algum Trues no booleano Series.

Sub-10
fonte
1

Condição simples:

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

Usar

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

Se xestiver presente id, retornará a lista de índices onde estiver presente, caso contrário, fornecerá uma lista vazia.

Ramana Sriwidya
fonte
1

Não sugiro usar "valor em série", o que pode gerar muitos erros. Consulte esta resposta para obter detalhes: Uso no operador com a série Pandas

Vicky Ding
fonte
0

Suponha que seu dataframe se pareça com:

insira a descrição da imagem aqui

Agora você deseja verificar se o nome do arquivo "80900026941984" está presente no dataframe ou não.

Você pode simplesmente escrever:

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