Возникла проблема с фильтрацией моего фрейма данных результата с условием или. Я хочу, чтобы мой результат df извлекал все значения столбца var, которые выше 0,25 и ниже -0,25.

Эта логика, приведенная ниже, дает мне неоднозначное значение истинности, однако она работает, когда я разделяю эту фильтрацию на две отдельные операции. Что здесь происходит? не уверен, где использовать предлагаемые a.empty (), a.bool (), a.item (), a.any () или a.all ().

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

Ответы (11)

Для операторов Python или и и требуются значения true. Для pandas они считаются неоднозначными, поэтому вы должны использовать «побитовые» операции | (или) или & (и):

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

Они перегружены для таких структур данных, чтобы получить поэлементные или (или и).


Просто чтобы добавить к этому утверждению дополнительные пояснения:

Исключение генерируется, когда вы хотите получить 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 (вы использовали или, но это также происходит для и, если и , а):

>>> 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, но для полноты я хотел бы упомянуть о них.


В вашем случае исключение не очень полезно, потому что в нем не упоминаются правильные альтернативы. Для и и или вы можете использовать (если хотите поэлементное сравнение):

  • numpy.logical_or:

    >>> импортировать numpy как np
    >>> np.logical_or (x, y)
    

    или просто оператор |:

    >>> x | у
    
  • numpy.logical_and:

    >>> np.logical_and (x, y)
    

    или просто оператор &:

    >>> x и y
    

Если вы используете операторы, убедитесь, что вы правильно установили скобки, поскольку приоритет оператора.

Есть несколько логических функций numpy, которые должны работать на pandas.Series.


Альтернативы, упомянутые в исключении, более подходят, если вы столкнулись с ним при выполнении if или при. Я кратко объясню каждый из них:

  • Если вы хотите проверить, является ли ваша серия пустой:

    >>> x = pd.Series ([])
    >>> x.empty
    Истинный
    >>> x = pd.Series ([1])
    >>> x.empty
    Ложь
    

    Python обычно интерпретирует length контейнеров (например, list, tuple, ...) как значение истины, если он не имеет явной логической интерпретации . Поэтому, если вам нужна проверка, подобная питону, вы можете сделать: , если x.size или , если не x.empty вместо , если x.

  • Если ваша Серия содержит одно и только одно логическое значение:

    >>> x = pd.Series ([100])
    >>> (x> 50) .bool ()
    Истинный
    >>> (х <50) .bool ()
    Ложь
    
  • Если вы хотите проверить первый и единственный элемент вашей серии (например, .bool (), но работает даже для не логического содержимого):

    >>> x = pd.Series ([100])
    >>> x.item ()
    100
    
  • Если вы хотите проверить, является ли все или любой элемент ненулевым, непустым или не-ложным:

    >>> x = pd.Series ([0, 1, 2])
    >>> x.all () # потому что один элемент равен нулю
    Ложь
    >>> x.any () # потому что один (или несколько) элементов не равны нулю
    Истинный
    
• 100001 из 2 полей.

Для логической логики используйте & и |.

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

Если у вас есть несколько критериев, вы получите несколько столбцов. Вот почему логика соединения неоднозначна. Использование и или или обрабатывает каждый столбец отдельно, поэтому вам сначала нужно уменьшить этот столбец до одного логического значения. Например, чтобы узнать, истинно ли какое-либо значение или все значения в каждом из столбцов.

# 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

Подробнее см. Boolean Indexing в документации.

Этот отличный ответ очень хорошо объясняет, что происходит, и предлагает решение. Я хотел бы добавить еще одно решение, которое могло бы подойти в аналогичных случаях: с помощью метода query:

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

См. Также http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-запрос.

(Некоторые тесты с фреймворком данных, с которым я сейчас работаю, предполагают, что этот метод немного медленнее, чем использование побитовых операторов для ряда логических значений: 2 мс против 870 мкс)

Предупреждение: По крайней мере, одна ситуация, когда это непросто, - это когда имена столбцов являются выражениями Python. У меня были столбцы с именами WT_38hph_IP_2, WT_38hph_input_2 и log2 (WT_38hph_IP_2 / WT_38hph_input_2), и я хотел выполнить следующий запрос: * 100010_2 * "(log2_WIP_38hphph )> 1) и (WT_38hph_IP_2> 20) "

Я получил следующий каскад исключений:

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

Полагаю, это произошло из-за того, что синтаксический анализатор запросов пытался сделать что-то из первых двух столбцов вместо того, чтобы идентифицировать выражение с именем третьего столбца.

Предлагается возможный обходной путь здесь.

Я получал ошибку в этой команде:

если df! = '': пройти

Но это сработало, когда я поменял его на это:

if df is not '': pass

Я попробую дать тест из трех наиболее распространенных способов (также упомянутых выше):

от повтора импорта timeit

setup = "" "
импортировать numpy как np;
случайный импорт;
x = np.linspace (0,100);
lb, ub = np.sort ([random.random () * 100, random.random () * 100]). tolist ()
"" "
stmts = 'x [(x> lb) * (x <= ub)]', 'x [(x> lb) & (x <= ub)]', 'x [np.logical_and (x> lb, x <= ub)] '

для _ в диапазоне (3):
    для stmt в stmts:
        t = мин (повтор (stmt, setup, number = 100_000))
        печать ('%. 4f'% t, stmt)
    Распечатать()

результат:

0.4808 x[(x > lb) * (x <= ub)]
0.4726 x[(x > lb) & (x <= ub)]
0.4904 x[np.logical_and(x > lb, x <= ub)]

0.4725 x[(x > lb) * (x <= ub)]
0.4806 x[(x > lb) & (x <= ub)]
0.5002 x[np.logical_and(x > lb, x <= ub)]

0.4781 x[(x > lb) * (x <= ub)]
0.4336 x[(x > lb) & (x <= ub)]
0.4974 x[np.logical_and(x > lb, x <= ub)]

Но, * не поддерживается в Panda Series, а массив NumPy быстрее, чем кадр данных pandas (примерно в 1000 раз медленнее, см. Число):

от повтора импорта timeit

setup = "" "
импортировать numpy как np;
случайный импорт;
импортировать панд как pd;
х = pd.DataFrame (np.linspace (0,100));
lb, ub = np.sort ([random.random () * 100, random.random () * 100]). tolist ()
"" "
stmts = 'x [(x> lb) & (x <= ub)]', 'x [np.logical_and (x> lb, x <= ub)]'

для _ в диапазоне (3):
    для stmt в stmts:
        t = мин (повтор (stmt, setup, number = 100))
        печать ('%. 4f'% t, stmt)
    Распечатать()

результат:

0,1964 x [(x> фунт) & (x <= ub)]
0,1992 x [np.logical_and (x> lb, x <= ub)]

0,2018 x [(x> фунт) & (x <= ub)]
0,1838 x [np.logical_and (x> lb, x <= ub)]

0,1871 x [(x> фунт) & (x <= ub)]
0,1883 x [np.logical_and (x> lb, x <= ub)]

Примечание: для добавления одной строки кода x = x.to_numpy () потребуется около 20 мкс.

Для тех, кто предпочитает % timeit:

import numpy as np
import random
lb, ub = np.sort([random.random() * 100, random.random() * 100]).tolist()
lb, ub
x = pd.DataFrame(np.linspace(0,100))

def asterik(x):
    x = x.to_numpy()
    return x[(x > lb) * (x <= ub)]

def and_symbol(x):
    x = x.to_numpy()
    return x[(x > lb) & (x <= ub)]

def numpy_logical(x):
    x = x.to_numpy()
    return x[np.logical_and(x > lb, x <= ub)]

for i in range(3):
    %timeit asterik(x)
    %timeit and_symbol(x)
    %timeit numpy_logical(x)
    print('\n')

результат:

23 µs ± 3.62 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
35.6 µs ± 9.53 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
31.3 µs ± 8.9 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)


21.4 µs ± 3.35 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
21.9 µs ± 1.02 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
21.7 µs ± 500 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)


25.1 µs ± 3.71 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
36.8 µs ± 18.3 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
28.2 µs ± 5.97 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Или, в качестве альтернативы, вы можете использовать модуль Operator. Более подробная информация здесь 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

Вам нужно использовать побитовые операторы | вместо или и & вместо и в пандах, вы просто не можете используйте операторы bool из python.

Для более сложной фильтрации создайте маску и примените маску к фрейму данных.
Поместите весь свой запрос в маску и примените его.
Допустим,

mask = (df["col1"]>=df["col2"]) & (stock["col1"]<=df["col2"])
df_new = df[mask]

Попробуйте
результат ['var']. All () если у вас более 1 значения Если это единственное значение, вы можете использовать result ['var']. Item ()

Одна мелочь, которая зря потратила мое время.

Поместите условия (при сравнении с использованием «=», «! =») В скобки, в противном случае также возникает это исключение. Это будет работать

df[(some condition) conditional operator (some conditions)]

Это не

df[some condition conditional-operator some condition]

Ну, панды используют побитовые & |, и каждое условие должно быть заключено в ()

Например следующие работы

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

Но тот же запрос без правильных скобок не

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

2022 WebDevInsider