Істинна цінність серії є неоднозначною. Використовуйте a.empty, a.bool (), a.item (), a.any () або a.all ()


366

Проблема з фільтруванням мого результату кадрів даних за orумови. Я хочу, щоб мій результат dfвитягнути всю колонкуvar витягнув значення що перевищують 0,25 і нижче -0,25.

Ця логіка нижче дає мені неоднозначне значення істини, однак воно працює, коли я розділив цю фільтрацію на дві окремі операції. Що тут відбувається? не знаєте, де використовувати запропоновані a.empty(), a.bool(), a.item(),a.any() or a.all().

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

46
використовувати |замістьor
MaxU

1
Ось таке рішення:abs(result['var'])>0.25
ColinMac

Відповіді:


566

Оператори orі andpython вимагають truth-значень. Бо pandasвони вважаються неоднозначними, тому вам слід використовувати операції "побітові" |(або) або &(і):

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

Вони перевантажені для подібних структур даних, щоб отримати елемент or(або and).


Просто додайте ще кілька пояснень до цього твердження:

Виняток , коли ви хочете отримати boolз 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().

Те , що ви потрапили був місцем , де оператор неявно перетвориться операнди bool(ви використовували , orале це також відбувається з- за and, ifі 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().

Крім того , ці 4 заяв є кілька функцій Python , які приховують деякі boolвиклики (наприклад any, all, filter, ...) це звичайно не викликають проблеми з , pandas.Seriesале для повноти картини я хотів згадати це.


У вашому випадку виняток насправді не корисний, оскільки він не згадує правильних альтернатив . Для andі orви можете використовувати (якщо ви хочете стихійне порівняння):

  • numpy.logical_or:

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

    або просто |оператор:

    >>> x | y
  • numpy.logical_and:

    >>> np.logical_and(x, y)

    або просто &оператор:

    >>> x & y

Якщо ви використовуєте операторів, то переконайтеся, що ви правильно встановили дужки через перевагу оператора .

Існує кілька логічних функцій numpi, над якими слід працювати pandas.Series.


Альтернативи, згадані у Винятку, більше підходять, якщо ви стикалися з ним під час ifчи while. Я коротко поясню кожне з них:

  • Якщо ви хочете перевірити, чи ваша серія порожня :

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

    Python зазвичай інтерпретує lenGTH контейнерів (наприклад list, tuple...) , як истинностное значення , якщо воно не має явне логічне тлумачення. Тож якщо ви хочете перевірити як пітон, ви можете зробити: if x.sizeабо if not x.emptyзамість if x.

  • Якщо ваше Seriesмістить одне і лише одне булеве значення:

    >>> x = pd.Series([100])
    >>> (x > 50).bool()
    True
    >>> (x < 50).bool()
    False
  • Якщо ви хочете перевірити перший і єдиний елемент вашої серії (наприклад, .bool()але працює навіть для не булевого вмісту):

    >>> x = pd.Series([100])
    >>> x.item()
    100
  • Якщо ви хочете перевірити, чи всі або будь-які елементи не є нульовими, не порожніми чи не-помилковими:

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

Чому ці оператори python не перевантажені для обробки серій панд?
Mudit Jain

@MuditJain Там немає ніякого способу безпосередньо від перевантаження and, orі notв Python. Ці оператори безпосередньо використовують те, що boolв операндах повертається. І певним чином Pandas / NumPy перевантажили, що вже підняти, ValueErrorтому що вони вважають цінність такої структури даних неоднозначною.
MSeifert

рішення нормально, але пояснення далеко не добре
чорношкірий

2
@blacksheep Чи є у вас пропозиції, що я міг би пояснити краще?
MSeifert

Це чудове пояснення. Це насправді допомогло мені зрозуміти побіжно та логічно таким чином, що не вдалося зробити більш абстрактних прикладів.
скеліNwaves

41

Для логічної логіки використовуйте &і |.

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

Щоб побачити, що відбувається, ви отримуєте стовпчик булів для кожного порівняння, наприклад

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

Якщо у вас є кілька критеріїв, ви отримаєте кілька повернених стовпців. Ось чому логіка з'єднання неоднозначна. Використання andабо orобробка кожного стовпця окремо, тому спочатку потрібно зменшити цей стовпець до одного булевого значення. Наприклад, щоб дізнатись, чи якесь значення чи всі значення в кожному з стовпців є істинним.

# 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

Один спільний спосіб досягти того самого - зібрати всі ці стовпці разом і виконати відповідну логіку.

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

Докладніше див. Булеву індексацію в документах.


20

Добре панди використовують побітне значення "&" "|" і кожна умова повинна бути загорнута у "()"

Наприклад, наступні роботи

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

Але той самий запит без належних дужок не робить

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

8

Або ж ви можете використовувати модуль Operator. Більш детальна інформація тут знаходиться в документах 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

Ця відмінна відповідь дуже добре пояснює, що відбувається, і забезпечує рішення. Я хотів би додати ще одне рішення, яке може бути придатним у подібних випадках: використовуючи queryметод:

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

Дивіться також http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-query .

(Деякі тести з фреймом даних, з яким я зараз працюю, припускають, що цей метод трохи повільніше, ніж використання операцій по порозрядних операціях для ряду булевих сигналів: 2 мс проти 870 мкс)

Попередження : Принаймні одна ситуація, коли це не є зрозумілим, коли назви стовпців бувають виразами python. У мене були стовпці з назвою WT_38hph_IP_2, WT_38hph_input_2іlog2(WT_38hph_IP_2/WT_38hph_input_2) й хотів виконати наступний запит:"(log2(WT_38hph_IP_2/WT_38hph_input_2) > 1) and (WT_38hph_IP_2 > 20)"

Я отримав наступний каскад винятків:

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

Я думаю, що це сталося тому, що аналізатор запитів намагався щось зробити з перших двох стовпців замість того, щоб ідентифікувати вираз із назвою третього стовпця.

Можливий спосіб обходу пропонується тут .


1

Я зіткнувся з тією ж помилкою і затримався з фреймом даних pyspark протягом декількох днів, мені вдалося її успішно вирішити, заповнивши значення значень 0, оскільки я порівнював цілі значення з 2 полів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.