Применение функций фильтра к фрейму данных

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

User_ID | Transaction_Type |   Date   | Amount
    1   |      Sale        | 01/01/14 | 200.00
    2   |     Purchase     | 01/01/14 |  30.00
    ...

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

Я пытаюсь создать функцию, которая будет проверять, выполнил ли пользователь оба действия или нет. Если пользователь сделал и то, и другое, то пользователь будет помечен как да, в противном случае нет.

До сих пор я пытался сделать это,

def user_filter(df):
if df in df['User_ID'].filter(lambda x : ((x['Transaction_Type']=='Sale').any())&((x['Transaction_Type']=='Purchase').any())):
    return 'yes'
else:
    return 'no'
df['cross'] = df['User_ID'].apply(user_filter)

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

User_ID | Transaction_Type |   Date   | Amount | cross
    1   |      Sale        | 01/01/14 | 200.00 |  yes
    2   |     Purchase     | 01/01/14 |  30.00 |   no

но возвращается следующая ошибка:

'int' object is not subscriptable

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

KeyError: ('User_ID', 'occurred at index User_ID')

Можете ли вы объяснить логику для cross? IIUC, cross=yes требует ОБА Sale и Purchase для такой жеUser_ID. Правильный? Ваш ожидаемый результат, вы показываете cross=yes для ТолькоSale. Это меня смущает.

edesz 07.04.2019 21:37

Вы подаете заявку на одну серию - User_Id попробуйте на весь df

Konrad 07.04.2019 21:39

@KonradSitarz Это возвращается KeyError: ('User_ID', 'occurred at index User_ID')

Kbbm 07.04.2019 21:40

@edesz следующее df['User_ID'].filter(lambda x : ((x['Transaction_Type']=='Sale').any())&((x['Transaction_Typ‌​e']=='Purchase').any‌​())) будет фильтровать только пользователей, которые являются обоими.

Kbbm 07.04.2019 21:43

@KyleMcComb: у User_ID=1 нет Sale. Тем не менее, этот пользователь назначен cross=yes. Согласно устным инструкциям, которые вы опубликовали, я бы подумал, что им следует назначать cross=no, а cross=yes следует назначать только в том случае, если такой жеUser_ID имеет Sale и Purchase. Просьба уточнить

edesz 07.04.2019 21:53

@edesz В моем фрейме данных более 1000 наблюдений, и пользователь 1 снова появляется как продажа. Я просто обрезал его. извините, что не прояснил это.

Kbbm 07.04.2019 22:01
Почему в 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
6
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Один из возможных подходов к этому — использовать groupby, а затем вместо агрегирования просто перечислить Transaction_Type в каждой группе, как показано в этот ТАК пост. Затем просто получите длину списка.... если длина равна 2, это означает, что для этого пользователя присутствуют как Sale, так и Purchase. С другой стороны, если длина равна 1, то для этого пользователя присутствует только один из Sale или Purchase.

Сгенерируйте некоторые данные для OP (я добавил третью запись, чтобы сделать вывод более явным)

d = [['User_ID', 'Transaction_Type', 'Date', 'Amount'],
    [1, 'Sale', '01/01/14', 200],
    [1, 'Purchase','01/02/14',300],
    [2, 'Purchase','01/01/14',30],]

Выполните GROUP BY

df_users = df.groupby('User_ID')['Transaction_Type'].apply(list).reset_index(drop=False)
df_users.rename(columns = {'Transaction_Type':'Transactions'}, inplace=True)

print(df_users)
   User_ID      Transactions
0        1  [Sale, Purchase]
1        2        [Purchase]

Теперь добавьте столбец cross к сгруппированному DataFrame и заполните столбец cross по мере необходимости.

df_users['cross'] = 'no'
df_users.loc[df_users.Transactions.apply(len)==2, 'cross'] = 'yes'

print(df_users)
   User_ID      Transactions cross
0        1  [Sale, Purchase]   yes
1        2        [Purchase]    no

РЕДАКТИРОВАТЬ 1

В качестве альтернативы, отбросьте шаги apply и просто используйте size

df_users = df.groupby('User_ID')['Transaction_Type'].size().reset_index(drop=False)
df_users['cross'] = 'no'
df_users.loc[df_users.Transactions==2, 'cross'] = 'yes'

print(df_users)
   User_ID  Transactions cross
0        1             2   yes
1        2             1    no

РЕДАКТИРОВАТЬ 2

Если вы хотите добавить столбец cross к источнику DataFrame, добавьте эти 2 строки кода к приведенному выше

df = df.merge(df_users, on='User_ID')
df.drop(columns=['Transactions'], inplace=True)

print(df)
   User_ID Transaction_Type      Date  Amount cross
0        1             Sale  01/01/14     200   yes
1        1         Purchase  01/02/14     300   yes
2        2         Purchase  01/01/14      30    no

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