首页 > 解决方案 > Pandas - 将列添加到数据框中,根据上个月的项目 ID 查找项目销售额的总和和平均值

问题描述

我有一个名为 grouped_train 的数据框,它按月列出了每个商店中每个商品的销售数量。这是数据框的示例。

date_block_num item_id shop_id item_cnt_month
0 32 0 6
0 32 5 1
0 26 1 3
0 26 18 9
1 32 46 1
1 26 50 2

有 33 个 date_block_nums 对应不同的月份。我想添加两列,列出上个月/date_block_num 中按 item_id 列出的所有销售额的总和,以及上个月所有 store_id 中该特定 item_id 的销售额平均值,其中 date_block_num == 0 的任何行都应该无。

因此,使用上面的示例 df,输出将如下所示:

date_block_num item_id shop_id item_cnt_month item_sales_prev_month mean_item_sales_prev_month
0 32 0 6 没有任何 没有任何
0 32 5 1 没有任何 没有任何
0 26 1 3 没有任何 没有任何
0 26 18 9 没有任何 没有任何
1 32 46 1 7 3.5
1 26 50 2 12 6

我已经为 sum_item_prev_month 列编写了一些代码,我认为这些代码可以工作并且可以轻松地更改它以创建平均销售额列,但是我的数据框中有超过 290 万行,我的代码需要多个小时才能运行。诚然,我并不精通 pandas,必须有一些我缺少的矢量化公式来加快计算速度。这是我到目前为止的代码。

sales_by_item_by_month = grouped_train.groupby(['date_block_num', 'item_id'], as_index=False).agg({'item_cnt_month' : 'sum'})

date_block_nums = list(grouped_train['date_block_num'])
item_ids = list(grouped_train['item_id'])

sales_for_item_prev_month = []

for index in range(len(item_ids)):
    if date_block_nums[index] == 0:
        sales_for_item_prev_month.append(None)
    else:
        sales = sales_by_item_by_month[(sales_by_item_by_month['item_id'] == item_ids[index]) & (sales_by_item_by_month['date_block_num'] == date_block_nums[index] - 1)]
        
        if len(sales) == 0:
            sales_for_item_prev_month.append(0)
        else:
            sales_for_item_prev_month.append(int(sales['item_cnt_month'].values))
        
grouped_train['item_sales_prev_month'] = sales_for_item_prev_month

任何建议将不胜感激!

标签: pythonpandasdataframe

解决方案


假设date_block_num是顺序的。

尝试计算总和和平均值,groupby agg然后将 1 递增date_block_num以将其与下一组对齐:

sum_means = df.groupby(['date_block_num', 'item_id']).agg(
    item_sales_prev_month=('item_cnt_month', 'sum'),
    mean_item_sales_prev_month=('item_cnt_month', 'mean')
).reset_index()
sum_means['date_block_num'] += 1

sum_means

   date_block_num  item_id  item_sales_prev_month  mean_item_sales_prev_month
0               1       26                     12                         6.0
1               1       32                      7                         3.5
2               2       26                      2                         2.0
3               2       32                      1                         1.0

然后merge回到原来的帧:

df = df.merge(sum_means, on=['date_block_num', 'item_id'], how='left')

df

   date_block_num  item_id  shop_id  item_cnt_month  item_sales_prev_month  mean_item_sales_prev_month
0               0       32        0               6                    NaN                         NaN
1               0       32        5               1                    NaN                         NaN
2               0       26        1               3                    NaN                         NaN
3               0       26       18               9                    NaN                         NaN
4               1       32       46               1                    7.0                         3.5
5               1       26       50               2                   12.0                         6.0

完整代码:

import pandas as pd

df = pd.DataFrame({
    'date_block_num': {0: 0, 1: 0, 2: 0, 3: 0, 4: 1, 5: 1},
    'item_id': {0: 32, 1: 32, 2: 26, 3: 26, 4: 32, 5: 26},
    'shop_id': {0: 0, 1: 5, 2: 1, 3: 18, 4: 46, 5: 50},
    'item_cnt_month': {0: 6, 1: 1, 2: 3, 3: 9, 4: 1, 5: 2}
})

sum_means = df.groupby(['date_block_num', 'item_id']).agg(
    item_sales_prev_month=('item_cnt_month', 'sum'),
    mean_item_sales_prev_month=('item_cnt_month', 'mean')
).reset_index()
sum_means['date_block_num'] += 1

df = df.merge(sum_means, on=['date_block_num', 'item_id'], how='left')

推荐阅读