如何将Pandas DataFrame按日期/产品组合扩展cost与quantity列
实现Pandas DataFrame按组展开为多列的方案
这是一个典型的数据宽表转换需求,咱们可以通过Pandas的分组标记、透视重塑两步搞定,下面一步步来:
步骤1:给每组内的记录添加序号
首先,我们需要给每个date+product组合下的每条记录分配一个从0开始的序号,这样后续才能对应到cost_n和quantity_n的下标:
df['idx'] = df.groupby(['date', 'product']).cumcount()
cumcount()会自动对每个分组内的行从0开始计数,完美标记每条记录在组内的位置。
步骤2:透视数据为宽表格式
接下来把数据转换成宽表,让每个序号对应的cost和quantity变成单独的列:
# 设置多级索引,然后展开最后一层(序号) wide_df = df.set_index(['date', 'product', 'idx']).unstack(level='idx')
这时候你会得到一个多层列名的DataFrame,列名格式类似('cost', 0)、('quantity', 1)这样。
步骤3:重命名列并填充缺失值
把多层列名改成cost_n、quantity_n的格式,同时把缺失的位置(组内记录数不足的部分)填充为0:
# 重命名列 wide_df.columns = [f'{col[0]}_{col[1]}' for col in wide_df.columns] # 填充NaN为0,并把date和product从索引转回列 wide_df = wide_df.fillna(0).reset_index()
完整示例代码
用你提供的样例数据测试一下:
import pandas as pd # 构造样例数据 data = { 'date': ['2018-01-02', '2018-01-02', '2018-01-02', '2018-01-04', '2018-01-04', '2018-01-04'], 'product': ['orange', 'apples', 'apples', 'melon', 'melon', 'melon'], 'cost': [7.5, 10, 12, 6.5, 5, 3.2], 'quantity': [2, 5, 4, 10, 4, 3] } df = pd.DataFrame(data) # 执行转换 df['idx'] = df.groupby(['date', 'product']).cumcount() wide_df = df.set_index(['date', 'product', 'idx']).unstack(level='idx') wide_df.columns = [f'{col[0]}_{col[1]}' for col in wide_df.columns] wide_df = wide_df.fillna(0).reset_index() print(wide_df)
运行后就能得到你想要的结果:
date product cost_0 cost_1 cost_2 quantity_0 quantity_1 quantity_2 0 2018-01-02 apples 10.0 12.0 0.0 5 4 0 1 2018-01-02 orange 7.5 0.0 0.0 2 0 0 2 2018-01-04 melon 6.5 5.0 3.2 10 4 3
注意事项
- 如果你的原DataFrame还有其他列(就是示例里的
...部分),只要这些列在同一个date+product组内的值是唯一的,直接把它们加入set_index的参数里即可,转换后会自动保留这些列。 - 如果组内的最大记录数是N,那么最终会生成
cost_0到cost_{N-1}、quantity_0到quantity_{N-1}的所有列,不足的部分自动补0。
内容的提问来源于stack exchange,提问作者Alessandro Ceccarelli
相关产品推荐
相关产品推荐

