Я продолжаю получать ошибку «функция не повторяется» с фильтром Pandas DataFrame, но та же функция работает с применением. Что мне не хватает?

TypeError: 'function' object is not iterable

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

Чего мне не хватает, когда я решаю использовать «фильтр» (который мне кажется более аккуратным, чем использование «loc» для достижения того же результата), и почти всегда получаю эту ошибку.

Вот простой пример.

import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.rand(4,4), columns=['a', 'b', 'c', 'd'])
df.filter(lambda x:x['b'] > 0.5, axis=1)
Traceback (most recent call last):

  Cell In[190], line 1
    df.filter(lambda x:x['b'] > 0.5, axis=1)

  File ~/.local/lib/python3.8/site-packages/pandas/core/generic.py:5454 in filter
    return self.reindex(**{name: [r for r in items if r in labels]})

TypeError: 'function' object is not iterable

In [1]: df.apply(lambda x:x['b'] > 0.5, axis=1)
Out[1]: 
0     True
1     True
2    False
3    False
dtype: bool


In [2]: df.loc[df['b']> 0.5]
Out[2]: 
          a        b         c         d
0  0.578342  0.82178  0.414652  0.630859
1  0.181232  0.91806  0.772260  0.502921

Даже самая простая лямбда-функция создает ошибку, например:

In [5]: tru = lambda x: True

In [6]: df['b'].filter(tru)
Traceback (most recent call last):

  Cell In[196], line 1
    df['b'].filter(tru)

  File ~/.local/lib/python3.8/site-packages/pandas/core/generic.py:5454 in filter
    return self.reindex(**{name: [r for r in items if r in labels]})

TypeError: 'function' object is not iterable

# Once again

In [7]: df['b'].apply(tru)
Out[7]: 
0    True
1    True
2    True
3    True
Name: b, dtype: bool

На мой взгляд, filter требует функции, возвращающей логическое значение, что, очевидно, и делает упрощенный пример, но filter терпит неудачу и снова apply работает. Что находится «под капотом», что влияет на результат?

Как объяснялось выше, я попробовал df.filter(function), но это не удалось. df.loc[df.apply(function)] дает правильный результат.

Это недопустимое использование функционального фильтра. Вы используете функцию фильтра класса Dataframe, и фильтр не принимает функцию в качестве своего параметра (например, лямбда-функцию, которую вы передаете). Посмотрите документацию о том, как фильтр работает в фрейме данных. обратите внимание, что это не функция фильтра типичного списка (встроенная функция фильтра, которая работает с любой итерацией), которую вы видите в Python, которая отличается. pandas.pydata.org/docs/reference/api/…

Srinjoy Choudhury 14.06.2024 14:15
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
1
57
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

df.filter используется для «[s]подстановки строк или столбцов фрейма данных в соответствии с указанными метками индекса».

Например, df.filter на индексных метках дает вам соответствующее подмножество:

df.filter([0,1], axis=0)

          a         b         c         d
0  0.550798  0.708148  0.290905  0.510828
1  0.892947  0.896293  0.125585  0.207243

То же самое с метками столбцов:

df.filter(['c', 'd'], axis=1)

          c         d
0  0.290905  0.510828
1  0.125585  0.207243
2  0.029876  0.456833
3  0.676255  0.590863

Чтобы выполнить фильтр того типа, который вы хотите получить, обычно используется логическое индексирование:

import pandas as pd
import numpy as np

np.random.seed(3) # for reproducibility
df = pd.DataFrame(np.random.rand(4,4), columns=['a', 'b', 'c', 'd'])

cond = df['b'] > 0.5

df[cond]

          a         b         c         d
0  0.550798  0.708148  0.290905  0.510828
1  0.892947  0.896293  0.125585  0.207243

По крайней мере, в вашем примере альтернативой может быть df.query:

df.query('b > 0.5')

          a         b         c         d
0  0.550798  0.708148  0.290905  0.510828
1  0.892947  0.896293  0.125585  0.207243

Возможные путаницы

  • Встроенный фильтр Python

Для использования встроенного filter в Python требуется итерация, а pd.DataFrame сам по себе не является итерацией. Например, вам придется использовать что-то вроде df.iterrows, а затем потом перестроить df:

pd.DataFrame([row[1] for row in filter(lambda x: x[1]['b'] > 0.5, 
                                       df.iterrows())], 
             columns=df.columns)

          a         b         c         d
0  0.550798  0.708148  0.290905  0.510828
1  0.892947  0.896293  0.125585  0.207243

Как видите, это довольно абсурдный поступок.

Несколько сбивает с толку то, что эта функция работает иначе, чем df.filter, и имеет другую цель, а именно фильтровать целые группы по одному или нескольким групповым условиям.

Например, если мы разделим наш df на две группы: индексы 0, 2, 3 и 1, мы сможем сделать что-то вроде этого:

df.groupby([1,2,1,1]).filter(lambda x: (x['b'] > 0.5).all())

          a         b         c         d
1  0.892947  0.896293  0.125585  0.207243

# row `0` will be filtered out, since other group members fail test

Имейте в виду, что groupby.filter зачастую не самый эффективный вариант, особенно при работе с простыми агрегатами. Например, рассмотрим следующее:

import pandas as pd
import numpy as np

np.random.seed(0) # for reproducibility

N = 10_000

data = {'a': np.random.choice(np.arange(500), size=N, replace=True),
        'b': np.random.rand(N)}

df = pd.DataFrame(data)

gr_transform = lambda df: df[df.groupby('a')['b'].transform('count') > 20]
gr_filter = lambda df: df.groupby('a').filter(lambda x: x['b'].count() > 20)

gr_filter(df).equals(gr_transform(df))
# True

%timeit gr_transform(df)
# 746 µs ± 23.2 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

%timeit gr_filter(df)
# 30.5 ms ± 731 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

Здесь groupby.transform с логическим индексированием легко превосходит groupby.filter.

Обратите внимание, что вы можете использовать df.loc[lambda x: x['b'] > 0.5], чтобы действовать как питон filter ;)

mozway 14.06.2024 14:35

@ouroboros и @ Пол Уилсон, ааа. Да, ты прав. Но не путайте с «фильтром» Python, а с фильтром pandas gruopby. С группой я могу делать такие вещи, как grp.filter(lambda x: x['b'].count() > 2), предполагая, что группировка была создана. Но для этого всегда требуется наличие агрегатирующей функции.

John Tweed 15.06.2024 13:00

Я приму ваш ответ, поскольку он охватывает как минимум 2 (правильных) альтернативы с использованием loc или запроса.

John Tweed 15.06.2024 13:17

@JohnTweed: понятно. Да, это немного сбивает с толку. Немного реструктуризировал мою пятерку, чтобы убрать потенциальную путаницу в конце, добавив df.groupby.filter, а затем потенциальную проблему с производительностью. Надеюсь, это полезно.

ouroboros1 15.06.2024 15:20

filter не выполняет функцию. Вам следует использовать loc[]

filter имеет несколько опций в pandas, но они основаны на фильтрации имен столбцов (или индексов), а не значений. Он не может принимать функцию в качестве аргумента. Вместо этого потребуется итерация, например список (в документации есть и другие варианты, но они основаны на той же предпосылке).

Ссылка Документация Pandas

Другие вопросы по теме