Pandas中按分组生成DAY列序数的高效实现方案
问题场景
处理长格式时间序列DataFrame,结构如下:
ACCOUNT | VAR1 | VAR2 | DAY
需要新增DAY_ORD列,为每个唯一的(ACCOUNT, VAR1, VAR2)分组内的DAY生成从0开始的序数排名,预期效果如下:
| ACCOUNT | VAR1 | VAR2 | DAY | DAY_ORD |
|---|---|---|---|---|
| A | X | True | 2022-02-03 | 0 |
| A | X | True | 2022-02-04 | 1 |
| B | X | True | 2021-05-18 | 0 |
| A | X | True | 2022-02-05 | 2 |
| B | X | True | 2022-05-20 | 1 |
| A | Y | True | 2022-02-05 | 0 |
| A | X | True | 2022-03-12 | 3 |
原实现代码运行速度极慢(约8次/秒),代码如下:
#initialize an empty 'DAY_ORD' column df['DAY_ORD'] = [None for i in range(len(df))] #iterate over all triplets that appear in the data for (_, row) in fb_data[['ACCOUNT', 'VAR1', 'VAR2']].copy().drop_duplicates().iterrows(): acc, v1, v2 = row[0], row[1], row[2] #find the df slice that adheres to the considered triplet fdf = df.loc[(df.ACCOUNT== acc) & (fb_data.VAR1 == v1) & (fb_data.VAR2 == v2)].sort_values('DAY') #assign them an ordinal rank fdf['DAY_ORD'] = [i for i in range(len(fdf))] #set the DAY_ORD values in the original dataframe for i in fdf.index: df.loc[i, 'DAY_ORD'] = fdf['DAY_ORD'][i] df['DAY_ORD']
优化方案
原代码性能瓶颈在于嵌套循环+逐行赋值,完全未利用Pandas的向量化运算优势。以下是极简高效的实现方式:
高效代码
# 先按分组键和DAY排序,确保组内时间顺序正确 df = df.sort_values(['ACCOUNT', 'VAR1', 'VAR2', 'DAY']) # 分组生成从0开始的连续序数 df['DAY_ORD'] = df.groupby(['ACCOUNT', 'VAR1', 'VAR2']).cumcount()
逻辑说明
sort_values:对分组字段和DAY排序,保证每个组内的时间序列是有序的,为生成正确序数提供前提。groupby:按指定的三个字段精准分组,定位每个需要生成序数的独立组。cumcount():Pandas内置方法,为每个分组内的行自动生成从0开始的连续整数,完全匹配需求中的序数排名逻辑。
额外提示
如果确认原始数据中每个(ACCOUNT, VAR1, VAR2)分组内的DAY已经是有序状态,可以省略sort_values步骤,直接调用cumcount()即可。
内容的提问来源于stack exchange,提问作者Vid Stropnik
相关产品推荐
相关产品推荐

