Estou trabalhando com índice booleano no Pandas. A questão é por que a afirmação:
a[(a['some_column']==some_number) & (a['some_other_column']==some_other_number)]
funciona bem enquanto
a[(a['some_column']==some_number) and (a['some_other_column']==some_other_number)]
sai com erro?
Exemplo:
a=pd.DataFrame({'x':[1,1],'y':[10,20]})
In: a[(a['x']==1)&(a['y']==10)]
Out: x y
0 1 10
In: a[(a['x']==1) and (a['y']==10)]
Out: ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
and != &
. Oand
operador no Python não pode ser substituído, enquanto o&
operador (__and__
) pode. Daí a escolha do uso&
em numpy e pandas.Respostas:
Quando voce diz
Você está pedindo implicitamente ao Python que converta
(a['x']==1)
e(a['y']==10)
valores booleanos.Matrizes NumPy (de comprimento maior que 1) e objetos Pandas como Series não possuem um valor booleano - em outras palavras, eles aumentam
quando usado como um valor booleano. Isso porque não está claro quando deve ser Verdadeiro ou Falso . Alguns usuários podem assumir que são True se tiverem um comprimento diferente de zero, como uma lista Python. Outros podem desejar que isso seja verdadeiro apenas se todos os seus elementos forem verdadeiros. Outros podem querer que seja True se algum de seus elementos for True.
Como existem muitas expectativas conflitantes, os designers do NumPy e Pandas se recusam a adivinhar e, em vez disso, aumentam um ValueError.
Em vez disso, você deve ser explícito, chamando o
empty()
,all()
ouany()
método para indicar qual comportamento você deseja.Nesse caso, no entanto, parece que você não deseja avaliação booleana, deseja lógica e elementos em termos de elementos . É isso que o
&
operador binário executa:retorna uma matriz booleana.
A propósito, como observa alexpmil , os parênteses são obrigatórios, pois
&
têm uma precedência de operador mais alta que==
. Sem os parênteses,a['x']==1 & a['y']==10
seria avaliado como oa['x'] == (1 & a['y']) == 10
que por sua vez seria equivalente à comparação encadeada(a['x'] == (1 & a['y'])) and ((1 & a['y']) == 10)
. Essa é uma expressão do formulárioSeries and Series
. O uso deand
com duas séries ativaria novamente o mesmoValueError
que acima. É por isso que os parênteses são obrigatórios.fonte
x and y
desencadeie a avaliação debool(x)
ebool(y)
. Python "primeiro avaliax
; sex
for falso, seu valor é retornado; caso contrário,y
é avaliado e o valor resultante é retornado." Portanto, a sintaxex and y
não pode ser usada para lógica lógica de elemento e desde apenasx
ouy
pode ser retornada. Por outro lado,x & y
gatilhosx.__and__(y)
e o__and__
método podem ser definidos para retornar o que quisermos.==
cláusula são obrigatórios .a['x']==1 & a['y']==10
retorna o mesmo erro da pergunta.TLDR; Operadores lógicos em Pandas são
&
,|
e~
, e parênteses(...)
é importante!Python é
and
,or
enot
operadores lógicos são projetados para trabalhar com escalares. Portanto, o Pandas teve que fazer um melhor e substituir os operadores bit a bit para obter a versão vetorizada (elemento a elemento) dessa funcionalidade.Portanto, o seguinte em python (
exp1
eexp2
são expressões que avaliam um resultado booleano) ...... será traduzido para ...
para pandas.
Se no processo de execução da operação lógica você obtiver a
ValueError
, precisará usar parênteses para agrupar:Por exemplo,
E assim por diante.
Indexação booleana : Uma operação comum é calcular máscaras booleanas através de condições lógicas para filtrar os dados. Pandas fornece três operadores:
&
para lógicas E,|
para OR lógico, e~
para lógicas não.Considere a seguinte configuração:
AND lógico
Por
df
acima, digamos que você gostaria de retornar todas as linhas onde a <5 e B> 5. Isso é feito por máscaras para cada condição de computação separadamente, e Anding eles.&
Operador Bitwise sobrecarregadoAntes de continuar, observe este trecho específico dos documentos, que declaram
Portanto, com isso em mente, o elemento elemento lógico AND pode ser implementado com o operador bit a bit
&
:E a etapa de filtragem subsequente é simplesmente,
Os parênteses são usados para substituir a ordem de precedência padrão dos operadores bit a bit, que têm maior precedência sobre os operadores condicionais
<
e>
. Consulte a seção Precedência do operador nos documentos python.Se você não usar parênteses, a expressão será avaliada incorretamente. Por exemplo, se você tentar acidentalmente algo como
É analisado como
O que se torna,
Que se torna (consulte os documentos python sobre comparação de operadores encadeados ),
O que se torna,
Que lança
Então, não cometa esse erro! 1
Evitando o agrupamento de parênteses
A correção é realmente bastante simples. A maioria dos operadores possui um método associado correspondente para DataFrames. Se as máscaras individuais forem construídas usando funções em vez de operadores condicionais, você não precisará mais agrupar por parens para especificar a ordem de avaliação:
Veja a seção Comparações flexíveis. . Para resumir, temos
Outra opção para evitar parênteses é usar
DataFrame.query
(oueval
):Eu documentei extensivamente
query
eeval
em Avaliação de Expressão Dinâmica em pandas usando pd.eval () .operator.and_
Permite que você execute esta operação de maneira funcional. Chama internamente
Series.__and__
que corresponde ao operador bit a bit.Você normalmente não precisará disso, mas é útil saber.
Generalizando:
np.logical_and
(elogical_and.reduce
)Outra alternativa é usar
np.logical_and
, que também não precisa de agrupamento de parênteses:np.logical_and
é um ufunc (Universal Functions) , e a maioria dos ufuncs tem umreduce
método. Isso significa que é mais fácil generalizarlogical_and
se você tiver várias máscaras para AND. Por exemplo, para máscaras ANDm1
em2
em3
com&
, você teria que fazerNo entanto, uma opção mais fácil é
Isso é poderoso, porque permite que você desenvolva uma lógica mais complexa (por exemplo, gerando dinamicamente máscaras em uma compreensão de lista e adicionando todas elas):
1 - Eu sei que estou falando sério sobre esse ponto, mas por favor, tenha paciência comigo. Este é um muito , muito erro de principiante comum, e deve ser explicado muito bem.
OR lógico
Pelo
df
exposto, suponha que você gostaria de retornar todas as linhas em que A == 3 ou B == 7.Bitwise Sobrecarregado
|
Se ainda não o fez, leia também a seção Lógica E acima, todas as advertências se aplicam aqui.
Como alternativa, esta operação pode ser especificada com
operator.or_
Chamadas
Series.__or__
sob o capô.np.logical_or
Para duas condições, use
logical_or
:Para várias máscaras, use
logical_or.reduce
:NÃO lógico
Dada uma máscara, como
Se você precisar inverter todos os valores booleanos (para que o resultado final seja
[False, False, True]
), poderá usar qualquer um dos métodos abaixo.Bit a bit
~
Novamente, as expressões precisam estar entre parênteses.
Isso chama internamente
Mas não o use diretamente.
operator.inv
Chama internamente
__invert__
a série.np.logical_not
Essa é a variante numpy.
Observe que
np.logical_and
pode ser substituído pornp.bitwise_and
,logical_or
combitwise_or
elogical_not
cominvert
.fonte
|
, o que é equivalente anumpy.bitwise_or
, em vez denumpy.logical_or
. Posso perguntar por que? Não foinumpy.logical_or
projetado especificamente para esta tarefa? Por que adicionar o ônus de fazê-lo bit a bit para cada par de elementos?|
para operação booleana em elementos. Mas para mim, essa documentação é mais um "tutorial" e, por outro lado, acho que essas referências à API estão mais próximas da fonte da verdade: numpy.bitwise_or e numpy.logical_or - então estou tentando entender o que é descrito aqui.É importante perceber que você não pode usar nenhum dos operadores lógicos do Python (
and
,or
ounot
) empandas.Series
oupandas.DataFrame
s (da mesma forma que você não pode usá-los emnumpy.array
s com mais de um elemento). A razão pela qual você não pode usá-los é porque eles implicitamente chamambool
seus operandos, o que gera uma exceção, porque essas estruturas de dados decidiram que o booleano de uma matriz é ambíguo:Eu cobri isso mais amplamente na minha resposta ao "Valor da verdade de uma série é ambíguo. Use a.empty, a.bool (), a.item (), a.any () ou a.all ()" Q + A .
Funções lógicas do NumPys
No entanto, o NumPy fornece equivalentes operacionais por elemento a esses operadores como funções que podem ser usadas
numpy.array
,pandas.Series
,pandas.DataFrame
, ou qualquer outro (em conformidade)numpy.array
subclasse:and
temnp.logical_and
or
temnp.logical_or
not
temnp.logical_not
numpy.logical_xor
que não tem equivalente em Python, mas é uma lógica operação "exclusiva ou"Então, essencialmente, deve-se usar (assumindo
df1
edf2
sendo panda DataFrames):Funções bit a bit e operadores bit a bit para booleanos
No entanto, se você tiver um array NumPy booleano, pandas Series ou pandas DataFrames, também poderá usar o funções bit a bit em elementos (para os booleanos, eles são - ou pelo menos devem ser - indistinguíveis das funções lógicas):
np.bitwise_and
ou o&
operadornp.bitwise_or
ou o|
operadornp.invert
(ou o aliasnp.bitwise_not
) ou o~
operadornp.bitwise_xor
ou o^
operadorNormalmente, os operadores são usados. No entanto, quando combinado com operadores de comparação, é necessário lembrar a comparação entre parênteses, porque os operadores bit a bit têm uma precedência mais alta que os operadores de comparação :
Isso pode ser irritante porque os operadores lógicos do Python têm uma precedência mais baixa do que os operadores de comparação; portanto, você normalmente escreve
a < 10 and b > 10
(em quea
eb
são, por exemplo, números inteiros simples) e não precisa de parênteses.Diferenças entre operações lógicas e bit a bit (em não booleanos)
É realmente importante enfatizar que operações lógicas e de bits são equivalentes apenas para matrizes NumPy booleanas (e Series e DataFrames booleanos). Se estes não contiverem booleanos, as operações fornecerão resultados diferentes. Vou incluir exemplos usando matrizes NumPy, mas os resultados serão semelhantes para as estruturas de dados do pandas:
E como o NumPy (e da mesma forma os pandas) faz coisas diferentes para os índices booleano ( matrizes de índice booleano ou "mascarado" ) e inteiro ( matrizes de índice ), os resultados da indexação também serão diferentes:
Tabela de resumo
Onde o operador lógico não funciona para matrizes NumPy , pandas Series e pandas DataFrames. Os outros trabalham nessas estruturas de dados (e objetos simples do Python) e trabalham em elementos. No entanto, tenha cuidado com o invertido bit a bit no Python simples,
bool
porque o bool será interpretado como número inteiro nesse contexto (por exemplo,~False
retornos-1
e~True
retornos-2
).fonte