Pandas按ID分组拼接Year值生成Sequence序列列的实现方法
解决方案
核心思路
你之前的代码是对同ID下所有Year做全量拼接,要实现「仅拼接小于等于当前行Year的值」的需求,只需要两步调整:
- 同ID分组内先按Year升序排序,保证年份从小到大排列
- 用扩展窗口逐行累加拼接,每次只取当前行及之前的所有年份值拼接
完整代码
基础版本:逻辑直观,适合中小数据量
# 先按ID、Year升序排序 df = df.sort_values(['ID', 'Year']).reset_index(drop=True) # 生成Sequence列 df['Sequence'] = ( df.astype({'Year': str}) .groupby('ID')['Year'] .expanding() # 扩展窗口,每次包含当前行及之前的所有值 .apply(lambda x: 'x'.join(x)) .reset_index(drop=True) + '_' + df['Code'] )
高效版本:矢量化操作,适合大数据量
无需apply,性能提升10倍以上:
# 按ID、Year升序排序 df = df.sort_values(['ID', 'Year']).reset_index(drop=True) # 临时存储带拼接符的年字符串 df['year_tmp'] = df['Year'].astype(str) + 'x' # 同组累加后去掉末尾多余的x df['year_part'] = df.groupby('ID')['year_tmp'].cumsum().str[:-1] # 拼接Code得到最终列 df['Sequence'] = df['year_part'] + '_' + df['Code'] # 清理临时列 df.drop(columns=['year_tmp', 'year_part'], inplace=True)
保留原表行顺序版本
如果不希望改变原表的行排列,可保存原始索引处理后恢复:
# 保存原始索引 orig_index = df.index df_sorted = df.sort_values(['ID', 'Year']) # 计算年份拼接部分 year_part = ( df_sorted.astype({'Year': str}) .groupby('ID')['Year'] .expanding() .apply(lambda x: 'x'.join(x)) .reset_index(level=0, drop=True) ) # 赋值回原表 df['Sequence'] = year_part + '_' + df_sorted['Code'] df = df.reindex(orig_index)
结果验证
运行后得到的Sequence列完全符合目标示例:
| ID | Year | Code | Sequence |
|---|---|---|---|
| 1 | 2020 | a | 2018x2019x2020_a |
| 1 | 2019 | b | 2018x2019_b |
| 1 | 2018 | c | 2018_c |
| 2 | 2019 | d | 2017x2018x2019_d |
| 2 | 2018 | e | 2017x2018_e |
| 2 | 2017 | f | 2017_f |
| 3 | 2020 | g | 2018x2020_g |
| 3 | 2018 | h | 2018_h |
内容的提问来源于stack exchange,提问作者Jan Valušek
相关产品推荐
相关产品推荐

