8

Неоднозначное значение истинности Series. Используйте a.empty, a.bool(), a.item(), a.any() или a.all()

13

Я хочу отфильтровать свой DataFrame по условию с использованием оператора or, чтобы оставить строки, значения определённого столбца которых находятся вне диапазона [-0.25, 0.25]. Я попытался сделать это следующим образом:

df = df[(df['col'] < -0.25) or (df['col'] > 0.25)]

Однако я получаю следующую ошибку:

ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

Как правильно применить условие or для фильтрации DataFrame в этом случае?

5 ответ(ов)

1

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

Пример корректного запроса:

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

Попытка выполнить тот же запрос без скобок приведет к ошибке:

data_query = data[(data['year'] >= 2005 & data['year'] <= 2010)]  # Это не сработает

Причина в том, что оператор & имеет более высокий приоритет, чем оператор сравнения >=, поэтому Python сначала пытается выполнить data['year'] >= 2005 & data['year'], что приводит к некорректному результату. Всегда оборачивайте условия в скобки, чтобы избежать такого поведения.

0

Если у вас есть более одного значения в столбце DataFrame, вы можете использовать метод all() для проверки, что все значения являются истинными:

df['col'].all()

Если у вас только одно значение, то для его получения следует использовать метод item(), который вернет это единственное значение:

df['col'].item()

Таким образом, all() подходит для проверки всех элементов в столбце, а item() — для извлечения одного значения.

0

Вы столкнулись с ошибкой из-за неправильного использования оператора сравнения. В Python для проверки того, что переменная не равна определенному значению, лучше использовать оператор is not вместо !=.

Вот объяснение вашего кода:

  1. Использование if df != '': будет работать, но вызывает некоторую путаницу, поскольку != — это оператор, который проверяет неравенство. Если df — это объект, а не строка, использование этого оператора может привести к неожиданным результатам.

  2. Запись if df is not '': является более предпочтительной в данном случае, поскольку is проверяет на идентичность объектов, а не просто на равенство значений. Однако стоит помнить, что для сравнения строк использование != или == предпочтительнее.

В общем, если вы хотите проверить, что строка df не пуста, используйте:

if df != '':
    pass

или, если вы хотите проверить пустой объект:

if bool(df):  # или просто if df:
    pass

Таким образом, оба применяемых метода будут более правильными в зависимости от контекста вашего кода.

0

Вам нужно использовать побитовые операторы | вместо or и & вместо and в библиотеке pandas. Нельзя просто использовать логические операторы из Python.

Для более сложной фильтрации лучше создать маску и применить её к DataFrame.

Соберите все свои условия в маску и примените её. Например:

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

В данном вопросе рассматриваются три наиболее распространенных способа фильтрации данных в NumPy и их производительность.

Для начала код был протестирован на массиве NumPy, где используются разные методы фильтрации:

from timeit import repeat

setup = """
import numpy as np
import random
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)]'

for _ in range(3):
    for stmt in stmts:
        t = min(repeat(stmt, setup, number=100_000))
        print('%.4f' % t, stmt)
    print()

Результаты выполнения показывают скорости для разных методов сравнения:

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

Как видно, использование * для булевой маски работает, но этот метод не поддерживается в pandas Series, что делает NumPy более быстрым в данном контексте. Тем не менее, NumPy быстрее pandas data frame (порядка 1000 раз).

Далее, код был протестирован на DataFrame от pandas:

from timeit import repeat

setup = """
import numpy as np
import random
import pandas as pd
x = 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)]'

for _ in range(3):
    for stmt in stmts:
        t = min(repeat(stmt, setup, number=100))
        print('%.4f' % t, stmt)
    print()

Результаты тестов для pandas выглядят следующим образом:

0.1964 x[(x > lb) & (x <= ub)]
0.1992 x[np.logical_and(x > lb, x <= ub)]

0.2018 x[(x > lb) & (x <= ub)]
0.1838 x[np.logical_and(x > lb, x <= ub)]

0.1871 x[(x > lb) & (x <= ub)]
0.1883 x[np.logical_and(x > lb, x <= ub)]

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

Для тех, кто предпочитает использовать %timeit, был проведен следующий тест:

import numpy as np
import random
import pandas as pd
lb, ub = np.sort([random.random() * 100, random.random() * 100]).tolist()
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)

Таким образом, использование & в pandas является предпочтительным способом фильтрации, так как это обеспечивает корректную работу и поддержку во всех структурах данных, даже несмотря на то, что метод * может показаться быстрее в случае с NumPy.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь