You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化Pandas中非连续重复section字段的分组重命名实现?

需求与问题

我管理着一个项目组合,每个项目都有独立的Excel表格用于跟踪时间、成本等数据。当前处理的DataFrame中,section字段存在非连续重复的情况,需要将同一section的不同连续分组进行编号区分(例如lift、lift (2)、lift (3))。我已经编写代码实现了需求,但希望得到更简洁优雅的优化方案。

原始数据

time cost section error other
0    1  500    lift          E1
1    2  100    lift          E2
2    1  400    wait          E3
3    4  200    lift    D4    E4
4    5  500    lift          E5
5    2  322   crash          E3
6    3  500    lift          E1
7    3  200    wait    D5    E2

期望结果

time cost   section error other
0    1  500      lift          E1
1    2  100      lift          E2
2    1  400      wait          E3
3    4  200  lift (2)    D4    E4
4    5  500  lift (2)          E5
5    2  322     crash          E3
6    3  500  lift (3)          E1
7    3  200  wait (2)    D5    E2

当前实现代码

df = pd.DataFrame({
    'time': ['1', '2', '1', '4', '5', '2', '3', '3'],
    'cost': ['500', '100', '400', '200', '500', '322','500','200'],
    'section': ['lift', 'lift', 'wait', 'lift', 'lift', 'crash', 'lift','wait'],
    'error': ['', '', '', 'D4', '','','','D5'],
    'other': ['E1', 'E2', 'E3', 'E4', 'E5','E3','E1','E2']}
    )
print(df)
# 检查当前行section是否与上一行相同
df['match'] = df.section.eq(df.section.shift())
# 若不同,将section值写入新列
df.loc[df['match'] == False, 'match2'] = df['section']
# 统计每个section的非连续出现次数
df.loc[df['match'] == False, 'match3'] = df.groupby(['match2']).cumcount()+1

# 根据次数添加后缀
df.loc[df['match3'] == 1, 'match4'] = df['section']
df.loc[df['match3'] == 2, 'match4'] = df['section'] + ' (2)'
df.loc[df['match3'] == 3, 'match4'] = df['section'] + ' (3)'
df.loc[df['match3'] == 4, 'match4'] = df['section'] + ' (4)'
df.loc[df['match3'] == 5, 'match4'] = df['section'] + ' (5)'
df.loc[df['match3'] == 6, 'match4'] = df['section'] + ' (6)'

df['match4'] = df['match4'].ffill()
df['section'] = df['match4']
df.drop(['match', 'match2', 'match3', 'match4'], inplace=True, axis=1 )
print(df)

当前代码输出

time cost section error other
0    1  500    lift          E1
1    2  100    lift          E2
2    1  400    wait          E3
3    4  200    lift    D4    E4
4    5  500    lift          E5
5    2  322   crash          E3
6    3  500    lift          E1
7    3  200    wait    D5    E2
  time cost   section error other
0    1  500      lift          E1
1    2  100      lift          E2
2    1  400      wait          E3
3    4  200  lift (2)    D4    E4
4    5  500  lift (2)          E5
5    2  322     crash          E3
6    3  500  lift (3)          E1
7    3  200  wait (2)    D5    E2

优化方案

通过识别连续分组+分组内计数+批量生成后缀的方式大幅简化代码,避免多个中间列和重复的条件赋值:

import pandas as pd

df = pd.DataFrame({
    'time': ['1', '2', '1', '4', '5', '2', '3', '3'],
    'cost': ['500', '100', '400', '200', '500', '322','500','200'],
    'section': ['lift', 'lift', 'wait', 'lift', 'lift', 'crash', 'lift','wait'],
    'error': ['', '', '', 'D4', '','','','D5'],
    'other': ['E1', 'E2', 'E3', 'E4', 'E5','E3','E1','E2']}
)

# 1. 标记连续分组的起始点:当前行与上一行section不同时为True
group_starts = df['section'] != df['section'].shift()
# 2. 为每个连续分组分配唯一ID(全局分组编号)
df['group_id'] = group_starts.cumsum()
# 3. 按原始section分组,统计每个section下的连续分组出现次数
df['section_count'] = df.groupby('section')['group_id'].transform(lambda x: x.rank(method='dense').astype(int))
# 4. 生成新的section名称:仅当计数>1时添加后缀
df['section'] = df.apply(
    lambda row: f"{row['section']} ({row['section_count']})" if row['section_count'] > 1 else row['section'],
    axis=1
)
# 清理中间列
df.drop(['group_id', 'section_count'], axis=1, inplace=True)

print(df)

优化说明

  • 步骤1-2:通过cumsum()快速生成连续分组的唯一ID,避免手动标记和填充;
  • 步骤3:用rank(method='dense')直接统计每个section下的连续分组序号,替代多次分组和条件赋值;
  • 步骤4:用apply批量处理后缀生成,无需为每个计数写单独的条件语句,扩展性更强(支持任意次数的重复);
  • 整体代码更紧凑,逻辑清晰,中间列可一次性清理,减少冗余操作。

内容的提问来源于stack exchange,提问作者beltalowda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 02:45:31