Скользящая сумма, основанная на датах, добавление в условия, которые активно обновляют значения в Pandas Dataframe, если выполнены? - PullRequest
0 голосов
/ 02 мая 2019

Я вычисляю скользящие итоги продаж за последние 180 дней по идентификатору в Python, используя Pandas, и мне нужно иметь возможность обновить столбец продаж за последние 180 дней, если пользователь достигнет определенного порога. Например, если кто-то достигает 100 долларов, израсходованных совокупно за последние 180 дней, его совокупные расходы за этот день должны отражать его достижение на этом уровне и эффективное «погашение» этих 100 долларов, оставляя их только с избытком от последнего посещения как прогрессом в их следующем. 100 долларов (См. Пример ниже)

Мне также нужно создать отдельный фрейм данных во время этого процесса, содержащий только даты и user_ids для достижения 100 долларов, чтобы отслеживать, сколько раз был достигнут порог для всех пользователей.

Я как-то думал, что смогу использовать apply с условными выражениями, но не был уверен, как именно это будет работать, так как фрейм данных нужно обновлять на лету, чтобы рассчитать скользящие суммы на более поздние даты с учетом этого обновленного Всего. Другими словами, кумулятивные суммы для дат после того, как они достигли порога, должны быть скорректированы с учетом того факта, что они «погасили» 100 долларов.

Это то, что я до сих пор получаю, когда пользователь получает накопительную сумму. Я не знаю, возможно ли связать условные методы с применимыми к этому или каков лучший путь вперед.

order_data['rolling_sales_180'] = order_data.groupby('user_id').rolling(window='180D', on='day')['sales'].sum().reset_index(drop=True)

См. Пример ожидаемых результатов ниже. В строке 6 пользователь достигает 120 долларов, переступая порог в 100 долларов, но 100 долларов вычитается из его кумулятивной суммы на эту дату, и у него остается 20 долларов на эту дату, потому что это была сумма, превышающая порог в 100 долларов, который он провел в тот день. Затем он продолжает накапливать эти 20 долларов за свой следующий визит в течение 180 дней. Пользователь может пройти этот процесс много раз, зарабатывая много наград за разные 180-дневные периоды.

print(order_data)

         day  user_id   sales  \
0 2017-08-10      1      10   
1 2017-08-22      1      10   
2 2017-08-31      1      10   
3 2017-09-06      1      10   
4 2017-09-19      1      10   
5 2017-10-16      1      30   
6 2017-11-28      1      40   
7 2018-01-22      1      10   
8 2018-03-19      1      10   
9 2018-07-25      1      10   

   rolling_sales_180  
0              10  
1              20  
2              30  
3              40  
4              50  
5              80  
6              20  
7              30  
8              40  
9              20

Кроме того, как упомянуто выше, мне нужно создать отдельный фрейм данных на протяжении всего этого процесса с указанием дня, user_id, sales и roll_sales_180, который включает только все дни, в течение которых был достигнут порог в 100 долларов, чтобы подсчитать число раз эта цель достигнута. Смотрите ниже:

print(threshold_reached)

         day  user_id   sales  rolling_sales_180
0 2017-11-28      1      40        120
.
.
.

1 Ответ

0 голосов
/ 02 мая 2019

Если я правильно понимаю ваш вопрос, у вас должно работать следующее:

def groupby_rolling(grp_df):
    df = grp_df.set_index("day")
    cum_sales = df.rolling("180D")["sales"].sum()
    hundreds = (cum_sales // 100).astype(int)
    progress = cum_sales % 100
    df["rolling_sales_180"] = cum_sales
    df["progress"] = progress
    df["milestones"] = hundreds
    return df

result = df.groupby("user_id").apply(groupby_rolling)

Вывод этого (для предоставленного вами образца):

                    user_id  sales  rolling_sales_180  progress  milestones
user_id day                                                                
1       2017-08-10        1     10               10.0      10.0           0
        2017-08-22        1     10               20.0      20.0           0
        2017-08-31        1     10               30.0      30.0           0
        2017-09-06        1     10               40.0      40.0           0
        2017-09-19        1     10               50.0      50.0           0
        2017-10-16        1     30               80.0      80.0           0
        2017-11-28        1     40              120.0      20.0           1
        2018-01-22        1     10              130.0      30.0           1
        2018-03-19        1     10               90.0      90.0           0
        2018-07-25        1     10               20.0      20.0           0

Что groupby(...).apply(...) делает для каждой группы в исходном df, применяется предоставленная функция. В этом случае я инкапсулировал вашу сложную логику, которую в настоящее время невозможно выполнить с помощью простой операции группового преобразования, в простой для анализа основной функции.

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

...