Nilai kebenaran suatu Seri bersifat ambigu. Gunakan a.empty, a.bool (), a.item (), a.any () atau a.all ()

369

Mengalami masalah saat memfilter dataframe hasil saya dengan suatu orsyarat. Saya ingin hasil saya dfmengekstraksi semua varnilai kolom yang di atas 0,25 dan di bawah -0,25.

Logika di bawah ini memberi saya nilai kebenaran yang ambigu namun bekerja ketika saya membagi penyaringan ini dalam dua operasi terpisah. Apa yang terjadi disini? tidak yakin di mana harus menggunakan yang disarankan a.empty(), a.bool(), a.item(),a.any() or a.all().

 result = result[(result['var']>0.25) or (result['var']<-0.25)]
obab
sumber
46
gunakan |sebagai gantior
MaxU
1
Berikut ini solusinya:abs(result['var'])>0.25
ColinMac

Jawaban:

566

Pernyataan ordan andpython membutuhkan truthnilai-. Untuk pandasini dianggap ambigu sehingga Anda harus menggunakan operasi "bitwise" |(atau) atau &(dan):

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

Ini kelebihan beban untuk jenis struktur data untuk menghasilkan elemen-bijaksana or(atau and).


Hanya dengan menambahkan beberapa penjelasan pada pernyataan ini:

Pengecualian dibuang ketika Anda ingin mendapatkan booldari 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().

Apa yang Anda tekan adalah tempat di mana operator secara implisit mengubah operan ke bool(Anda menggunakan ortetapi juga terjadi untuk and, ifdan 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().

Selain 4 pernyataan ini ada beberapa fungsi python yang menyembunyikan beberapa boolpanggilan (seperti any, all, filter, ...) ini biasanya tidak bermasalah dengan pandas.Seriestapi untuk kelengkapan saya ingin menyebutkan ini.


Dalam kasus Anda, pengecualian tidak terlalu membantu, karena tidak menyebutkan alternatif yang tepat . Untuk anddan orAnda dapat menggunakan (jika Anda ingin perbandingan elemen-bijaksana):

  • numpy.logical_or:

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

    atau hanya |operator:

    >>> x | y
  • numpy.logical_and:

    >>> np.logical_and(x, y)

    atau hanya &operator:

    >>> x & y

Jika Anda menggunakan operator maka pastikan Anda mengatur tanda kurung dengan benar karena prioritas operator .

Ada beberapa fungsi numpy logis yang harus dikerjakan pandas.Series.


Alternatif yang disebutkan dalam Pengecualian lebih cocok jika Anda menemukannya saat melakukan ifatau while. Saya akan segera menjelaskan masing-masing:

  • Jika Anda ingin memeriksa apakah Seri Anda kosong :

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

    Python biasanya menafsirkan length kontainer (seperti list, tuple, ...) sebagai kebenaran-nilai jika tidak memiliki interpretasi boolean eksplisit. Jadi jika Anda ingin cek seperti python, Anda bisa melakukan: if x.sizeatau if not x.emptybukannya if x.

  • Jika Anda Seriesmengandung satu dan hanya satu nilai boolean:

    >>> x = pd.Series([100])
    >>> (x > 50).bool()
    True
    >>> (x < 50).bool()
    False
  • Jika Anda ingin memeriksa item pertama dan satu-satunya dari Seri Anda (suka .bool()tetapi berfungsi bahkan untuk konten yang tidak boolean):

    >>> x = pd.Series([100])
    >>> x.item()
    100
  • Jika Anda ingin memeriksa apakah semua atau semua item tidak-nol, tidak-kosong atau tidak-Salah:

    >>> 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
MSeifert
sumber
Mengapa operator python ini tidak kelebihan beban untuk menangani seri panda?
Mudit Jain
@MuditJain Tidak ada cara untuk langsung kelebihan and, ordan notPython. Operator ini secara langsung menggunakan apa boolyang dikembalikan operan. Dan dengan cara Pandas / NumPy kelebihan yang sudah menaikkan ValueErrorkarena mereka menganggap nilai kebenaran dari struktur data seperti itu ambigu.
MSeifert
solusinya ok, tapi penjelasannya jauh dari bagus
blacksheep
2
@blacksheep Apakah Anda punya saran apa yang bisa saya jelaskan lebih baik?
MSeifert
Itu penjelasan yang bagus. Ini benar-benar membantu saya memahami bitwise vs logis dengan cara contoh yang lebih abstrak telah gagal dilakukan.
rocksNwaves
41

Untuk logika boolean, gunakan &dan |.

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

Untuk melihat apa yang terjadi, Anda mendapatkan kolom boolean untuk setiap perbandingan, misalnya

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

Ketika Anda memiliki beberapa kriteria, Anda akan mendapatkan beberapa kolom kembali. Inilah sebabnya mengapa logika join bersifat ambigu. Menggunakan andatau ormemperlakukan setiap kolom secara terpisah, jadi pertama-tama Anda harus mengurangi kolom itu menjadi nilai boolean tunggal. Misalnya, untuk melihat apakah ada nilai atau semua nilai di setiap kolom Benar.

# 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

Salah satu cara berbelit-belit untuk mencapai hal yang sama adalah dengan zip semua kolom ini bersama-sama, dan melakukan logika yang sesuai.

>>> 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

Untuk detail lebih lanjut, lihat Pengindeksan Boolean dalam dokumen.

Alexander
sumber
20

Nah panda menggunakan bitwise '&' '|' dan setiap kondisi harus dibungkus dalam '()'

Misalnya karya berikut

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

Tetapi kueri yang sama tanpa tanda kurung tidak

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

Atau, sebagai alternatif, Anda dapat menggunakan modul Operator. Informasi lebih rinci ada di sini Python docs

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
Cảnh Toàn Nguyễn
sumber
1

Jawaban yang luar biasa ini menjelaskan dengan sangat baik apa yang sedang terjadi dan memberikan solusi. Saya ingin menambahkan solusi lain yang mungkin cocok dalam kasus serupa: menggunakan querymetode:

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

Lihat juga http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-query .

(Beberapa tes dengan kerangka data yang saat ini saya kerjakan menunjukkan bahwa metode ini sedikit lebih lambat daripada menggunakan operator bitwise pada serangkaian boolean: 2 ms vs 870 µs)

Sepotong peringatan : Setidaknya satu situasi di mana ini tidak langsung adalah ketika nama kolom kebetulan menjadi ekspresi python. Aku punya kolom bernama WT_38hph_IP_2, WT_38hph_input_2dan log2(WT_38hph_IP_2/WT_38hph_input_2)dan ingin melakukan query berikut:"(log2(WT_38hph_IP_2/WT_38hph_input_2) > 1) and (WT_38hph_IP_2 > 20)"

Saya memperoleh kaskade pengecualian berikut:

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

Saya kira ini terjadi karena parser kueri mencoba membuat sesuatu dari dua kolom pertama alih-alih mengidentifikasi ekspresi dengan nama kolom ketiga.

Solusi yang mungkin diusulkan di sini .

bli
sumber
1

Saya mengalami kesalahan yang sama dan macet dengan pyspark dataframe selama beberapa hari, saya berhasil menyelesaikannya dengan mengisi nilai-nilai na dengan 0 karena saya membandingkan nilai integer dari 2 bidang.

iretex
sumber