Пользовательская агрегация с условной суммой - PullRequest
3 голосов
/ 04 октября 2019

У меня есть фрейм данных, который выглядит следующим образом

enter image description here

В зависимости от действий пользователя (возможны четыре типа действий) Я хочу накапливать пользователяколичество денег в данный момент времени. Действия типа A и B представляют доход пользователя, действия типа C и D. представляют расходы пользователя.

Другими словами, я хочу получить что-то подобное в результате

enter image description here

Пользователь 1 сначала выполняет действие action_A и в результате получает 10. Тогда action_B дает нам 10 + 5 = 15. Action_C представляет потерю денег и дает использование 15 - 5 = 10. Наконец, action_D - это то же самое, что и C, и мы получаем 10 - 15 = -5.

Как я могуосуществить это с пандами? Я пробовал настраиваемое агрегирование, используя

expanding().apply(agg_func)

, но не получил удовлетворительного результата.

EDIT: код для создания фрейма данных

ids = [1,1,1,1,2,2]
dates = ['2019-03-07 13:54', '2019-03-07 16:07', '2019-03-10 19:20', '2019-03-10 19:20', '2016-03-07 14:47', '2016-03-09 11:07']
amounts = [10., 5., 5., 15., 2., 4.]
actions = ['action_A', 'action_B', 'action_C', 'action_D', 'action_A', 'action_B']
result = [10, 15, 10, -5, 2, 6]

pd.DataFrame({'user_id': ids, 'start_date': dates, 'amount': amounts, 'action': actions, 'result': result}, index=range(6))

Ответы [ 2 ]

3 голосов
/ 04 октября 2019

Несколько значений -1 по маске, созданной Series.isin и Series.mask и последним использованием GroupBy.cumsum:

df['result'] = (df['amount'].mask(df['action'].isin(['action_C','action_D']),
                                  df['amount'] * -1)
                           .groupby(df['user'])
                           .cumsum())
print (df['result'])
0    10.0
1    15.0
2    10.0
3    -5.0
4     2.0
5     6.0
Name: result, dtype: float64

Аналогичное решение со вспомогательной колонкой:

df['result'] = (df.assign(tmp = df['amount'].mask(df['action'].isin(['action_C','action_D']),
                                 df['amount']*-1))
                  .groupby('user')['tmp']
                  .cumsum())
1 голос
/ 04 октября 2019

Надеюсь, это даст вам подсказку:

Сначала я даю отрицательный знак действию, представляющему расходы.

df.loc[df.action.isin(['action_C','action_D'])].amount = -1 * df.loc[df.action.isin(['action_C','action_D'])].amount

, затем вы создаете столбец результата, подобный этому

df['result'] = df.amount.cumsum()
...