фильтрация Pandas DataFrame с использованием словаря - PullRequest
4 голосов
/ 17 октября 2019

У меня есть фрейм данных Pandas с несколькими столбцами, и я хотел бы отфильтровать его, чтобы получить подмножество, соответствующее определенным значениям в разных столбцах. Я использовал метод isin() и передал словарь, но продолжаю получать TypeError с сообщением TypeError: only list-like or dict-like objects are allowed to be passed to DataFrame.isin(), you passed a 'str'.

Ниже приведен пример проблемы:

x = pd.DataFrame({'surname':['wang','park','park'],'name':['tim','john','sam']})
display(x)

filt_dict = {'surname':'park'}

x[x.isin(filt_dict)]

Я ожидал две строки, где surname соответствует park, но вместо этого я получил TypeError.

Что дает?

Ответы [ 6 ]

1 голос
/ 17 октября 2019

Значения фильтра должны быть списками:

x = pd.DataFrame({'surname': ['wang', 'park', 'park'], 'name': ['tim', 'john', 'sam']})

d = {'surname': ['park']}

print(x.isin(d))

Выход

   surname   name
0    False  False
1     True  False
2     True  False
1 голос
/ 17 октября 2019

Как вам нужно фильтровать по значениям dict:

In [118]: x[x.surname.isin(filt_dict.values())]
Out[118]: 
  surname  name
1    park  john
2    park   sam
0 голосов
/ 17 октября 2019

Решения гибкие. Исходя из вашего ввода, одно из них:

Во-первых, чтобы исключить сообщение об ошибке, вводимый вами isin() ключ должен быть {'surname':['park']} отличным от {'surname':'park'}

Также,x[x.isin(filt_dict)] не даст вам то, что вы хотите, потому что x.isin(filt_dict) вернет кадр данных, отличный от серии. Чтобы исправить это, добавьте ['surname']:

x[x.isin(filt_dict)['surname']]
или
x[x.isin(filt_dict)[[*filt_dict][0]]]


output:

  surname  name
1    park  john
2    park   sam
0 голосов
/ 17 октября 2019
>>> x = [s for s in x.itertuples() if s.surname == filt_dict['surname']]
>>> x
[Pandas(Index=1, surname='park', name='john'), Pandas(Index=2, surname='park', name='sam')]

Надеюсь, это поможет.

0 голосов
/ 17 октября 2019

Это решение обеспечивает большую гибкость с точки зрения количества ключей и типа значений (list или str, int ...)

filt_dict = {'surname':'park','name':['tim','sam']}
for key in filt_dict:
    mask=pd.Series([False]*len(x))
    try:
        mask=x[key].isin(filt_dict[key]) 
    except:

        try:
            mask=x[key].eq(filt_dict[key])
        except:
            pass
     print(x[mask])

Вывод:

  surname  name
1    park  john
2    park   sam
  surname name
0    wang  tim
2    park  sam
0 голосов
/ 17 октября 2019

Вы можете построить маску с помощью np.logical_and (or) + reduce в зависимости от того, является ли условие любой строкой, которая удовлетворяет всем условиям, или любой строкой, которая удовлетворяет какому-либо условию соответственно.

m = np.logical_and.reduce([x[k] == v for k,v in filt_dict.items()])
# np.logical_or.reduce if an `|` condition

x[m]
#  surname  name
#1    park  john
#2    park   sam

Если вы хотите сделать немного более безопасным, чтобы разрешить несколько типов сравнений, мы можем использовать isin, когда мы передаем итерацию (это не строка) и проверки равенства в противном случае.

m = np.logical_and.reduce(
        [x[k].isin(v) if (hasattr(v, '__iter__') and not isinstance(v, str)) 
         else x[k] == v for k,v in filt_dict.items()])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...