Il valore di verità di una serie è ambiguo. Usa a.empty, a.bool (), a.item (), a.any () o a.all ()


369

Problemi con il filtraggio del mio frame di dati dei risultati con una orcondizione. Voglio che il mio risultato dfestragga tutti i varvalori di colonna superiori a 0,25 e inferiori a -0,25.

Questa logica di seguito mi dà un ambiguo valore di verità, tuttavia funziona quando divido questo filtro in due operazioni separate. Cosa sta succedendo qui? non sono sicuro di dove utilizzare il suggerito a.empty(), a.bool(), a.item(),a.any() or a.all().

 result = result[(result['var']>0.25) or (result['var']<-0.25)]

46
utilizzare |invece dior
MaxU

1
Ecco una soluzione alternativa:abs(result['var'])>0.25
ColinMac,

Risposte:


566

Le istruzioni ore andpython richiedono truth-valori. Per pandasquesti sono considerati ambigui, quindi è necessario utilizzare le operazioni "bit per bit" |(o) o &(e):

result = result[(result['var']>0.25) | (result['var']<-0.25)]

Questi sono sovraccarichi per questo tipo di strutture dati per produrre l'elemento saggio or(o and).


Solo per aggiungere qualche spiegazione in più a questa affermazione:

L'eccezione viene generata quando si desidera ottenere il booldi a pandas.Series:

>>> import pandas as pd
>>> x = pd.Series([1])
>>> bool(x)
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

Quello che hai colpito è stato un luogo in cui l'operatore ha convertito implicitamente gli operandi bool(hai usato orma succede anche per and, ife while):

>>> x or x
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> x and x
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> if x:
...     print('fun')
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> while x:
...     print('fun')
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

Oltre a questi 4 affermazioni ci sono diverse funzioni Python che nascondono alcune boolchiamate (come any, all, filter, ...) questi non sono normalmente problematico con pandas.Series, ma per completezza ho voluto parlare di questi.


Nel tuo caso l'eccezione non è davvero utile, perché non menziona le alternative giuste . Per ande orpuoi usare (se vuoi confronti a livello di elemento):

  • numpy.logical_or:

    >>> import numpy as np
    >>> np.logical_or(x, y)

    o semplicemente l' |operatore:

    >>> x | y
  • numpy.logical_and:

    >>> np.logical_and(x, y)

    o semplicemente l' &operatore:

    >>> x & y

Se si utilizzano gli operatori, assicurarsi di impostare correttamente la parentesi a causa della precedenza dell'operatore .

Esistono diverse funzioni logiche intorpidite che dovrebbero funzionare pandas.Series.


Le alternative menzionate nell'eccezione sono più adatte se l'hai incontrata durante l'esecuzione ifo while. Spiegherò brevemente ciascuno di questi:

  • Se vuoi verificare se la tua serie è vuota :

    >>> x = pd.Series([])
    >>> x.empty
    True
    >>> x = pd.Series([1])
    >>> x.empty
    False

    Python interpreta normalmente la length di contenitori (come list, tuple, ...) come valore di verità se non ha nessuna interpretazione esplicita booleano. Quindi, se vuoi il controllo simile a Python, potresti fare: if x.sizeo if not x.emptyinvece di if x.

  • Se il tuo Seriescontiene un solo valore booleano:

    >>> x = pd.Series([100])
    >>> (x > 50).bool()
    True
    >>> (x < 50).bool()
    False
  • Se vuoi controllare il primo e unico elemento della tua serie (come .bool()ma funziona anche per contenuti non booleani):

    >>> x = pd.Series([100])
    >>> x.item()
    100
  • Se si desidera verificare se tutto o qualsiasi elemento è diverso da zero, non vuoto o non falso:

    >>> x = pd.Series([0, 1, 2])
    >>> x.all()   # because one element is zero
    False
    >>> x.any()   # because one (or more) elements are non-zero
    True

Perché questi operatori Python non sono sovraccarichi per gestire le serie Panda?
Mudit Jain,

@MuditJain Non v'è alcun modo per direttamente il sovraccarico and, ore notin Python. Questi operatori utilizzano direttamente ciò che viene boolrestituito dagli operandi. E in un certo senso Pandas / NumPy lo ha già sovraccaricato ValueErrorperché considerano ambiguo il valore di verità di una tale struttura di dati.
MSeifert,

la soluzione è ok, ma la spiegazione è tutt'altro che buona
blacksheep

2
@blacksheep Hai qualche suggerimento su cosa avrei potuto spiegare meglio?
MSeifert,

È un'ottima spiegazione. In realtà mi ha aiutato a comprendere bit per bit o logico in un modo che esempi più astratti non sono riusciti a fare.
rocksNwaves

41

Per la logica booleana, utilizzare &e |.

np.random.seed(0)
df = pd.DataFrame(np.random.randn(5,3), columns=list('ABC'))

>>> df
          A         B         C
0  1.764052  0.400157  0.978738
1  2.240893  1.867558 -0.977278
2  0.950088 -0.151357 -0.103219
3  0.410599  0.144044  1.454274
4  0.761038  0.121675  0.443863

>>> df.loc[(df.C > 0.25) | (df.C < -0.25)]
          A         B         C
0  1.764052  0.400157  0.978738
1  2.240893  1.867558 -0.977278
3  0.410599  0.144044  1.454274
4  0.761038  0.121675  0.443863

Per vedere cosa sta succedendo, ricevi una colonna di booleani per ogni confronto, ad es

df.C > 0.25
0     True
1    False
2    False
3     True
4     True
Name: C, dtype: bool

Quando hai più criteri, otterrai più colonne restituite. Questo è il motivo per cui la logica di join è ambigua. L'uso ando il ortrattamento di ciascuna colonna separatamente, quindi è necessario prima ridurre quella colonna a un singolo valore booleano. Ad esempio, per vedere se qualsiasi valore o tutti i valori in ciascuna delle colonne è True.

# Any value in either column is True?
(df.C > 0.25).any() or (df.C < -0.25).any()
True

# All values in either column is True?
(df.C > 0.25).all() or (df.C < -0.25).all()
False

Un modo contorto per ottenere la stessa cosa è comprimere tutte queste colonne ed eseguire la logica appropriata.

>>> df[[any([a, b]) for a, b in zip(df.C > 0.25, df.C < -0.25)]]
          A         B         C
0  1.764052  0.400157  0.978738
1  2.240893  1.867558 -0.977278
3  0.410599  0.144044  1.454274
4  0.761038  0.121675  0.443863

Per ulteriori dettagli, consultare Indicizzazione booleana nei documenti.


20

Bene i panda usano bitwise '&' '|' e ogni condizione dovrebbe essere racchiusa in un '()'

Ad esempio i seguenti lavori

data_query = data[(data['year'] >= 2005) & (data['year'] <= 2010)]

Ma la stessa query senza parentesi appropriate no

data_query = data[(data['year'] >= 2005 & data['year'] <= 2010)]

8

Oppure, in alternativa, è possibile utilizzare il modulo operatore. Informazioni più dettagliate sono qui documenti Python

import operator
import numpy as np
import pandas as pd
np.random.seed(0)
df = pd.DataFrame(np.random.randn(5,3), columns=list('ABC'))
df.loc[operator.or_(df.C > 0.25, df.C < -0.25)]

          A         B         C
0  1.764052  0.400157  0.978738
1  2.240893  1.867558 -0.977278
3  0.410599  0.144044  1.454274
4  0.761038  0.121675  0.4438

1

Questa eccellente risposta spiega molto bene cosa sta succedendo e fornisce una soluzione. Vorrei aggiungere un'altra soluzione che potrebbe essere adatta in casi simili: usando il querymetodo:

result = result.query("(var > 0.25) or (var < -0.25)")

Vedi anche http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-query .

(Alcuni test con un dataframe con cui sto attualmente lavorando suggeriscono che questo metodo è un po 'più lento rispetto all'utilizzo degli operatori bit a bit su serie di valori booleani: 2 ms contro 870 µs)

Un avvertimento : almeno una situazione in cui ciò non è semplice è quando i nomi delle colonne sono espressioni di Python. Ho avuto colonne denominate WT_38hph_IP_2, WT_38hph_input_2ed log2(WT_38hph_IP_2/WT_38hph_input_2)e volevo eseguire la seguente query:"(log2(WT_38hph_IP_2/WT_38hph_input_2) > 1) and (WT_38hph_IP_2 > 20)"

Ho ottenuto la seguente cascata di eccezioni:

  • KeyError: 'log2'
  • UndefinedVariableError: name 'log2' is not defined
  • ValueError: "log2" is not a supported function

Immagino che ciò sia accaduto perché il parser di query stava cercando di creare qualcosa dalle prime due colonne invece di identificare l'espressione con il nome della terza colonna.

Una possibile soluzione alternativa è proposta qui .


1

Ho riscontrato lo stesso errore e mi sono bloccato per alcuni giorni con un frame di dati pyspark, sono stato in grado di risolverlo con successo riempiendo i valori na con 0 poiché stavo confrontando i valori interi da 2 campi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.