如何遍历groupby分组对象并为组内行添加顺序编号列
问题
我正在处理一个包含2014年以来本市所有警方拦截记录的大型数据集,数据行数达数百万。同一拦截事件可能对应多行记录(如拦截4人则生成4行)。我需要为数据集新增orderInStop列,用于标记同一拦截事件内人员的被拦截顺序,第1人值为1,第2人值为2,依此类推。
我已使用groupby()函数按Date_Time_Occur和Location字段分组,将同一拦截事件的行归为一组。目前我能生成记录组内总人数的列,但无法实现组内行的顺序编号。以下是我尝试的代码:
生成组内总计数的代码:
df['order2'] = df.groupby(by=["Date_Time_Occur", "Location"])['orderInStop'].transform('count')
遍历分组失败的代码:
df['order3'] = 1 grp = df.groupby(by=["Date_Time_Occur", "Location"]) for name, groups in grp: count = 1 for row in groups: df['order3'] = count count = count + 1
注:我也曾尝试用循环结合逻辑运算符判断前后行的时间和位置是否匹配,但遭遇the truth values of a Series is ambiguous错误,因此改用groupby()方案。
解决方案
问题根源
你之前的循环代码有两个关键错误:
- 遍历
groups时,row取到的是列名而非行数据,无法定位到具体行; - 直接执行
df['order3'] = count会把整个列的值覆盖为当前count,而非给分组内的对应行赋值。
另外,嵌套循环处理百万级数据效率极低,完全不符合Pandas的最佳实践。
高效实现代码
Pandas内置的cumcount()方法专门用于生成组内递增序号,默认从0开始,加1即可得到从1起始的顺序编号,且是向量化操作,性能拉满:
# 生成同一拦截事件内的人员顺序编号 df['orderInStop'] = df.groupby(by=["Date_Time_Occur", "Location"]).cumcount() + 1
关键说明
cumcount()会严格遵循原始数据集的行顺序,为每个分组内的行生成连续整数,加1后正好满足第1人=1、第2人=2的需求;- 该方法无需手动循环,处理百万级数据的速度远快于嵌套循环;
- 若你需要基于其他字段确定顺序(比如人员的拦截时间戳),可以先对分组内的数据排序再执行
cumcount(),示例如下:
# 先按分组内的拦截时间排序,再生成顺序号 df['orderInStop'] = df.groupby(by=["Date_Time_Occur", "Location"])['Person_Stop_Time'].rank(method='first').astype(int)
内容的提问来源于stack exchange,提问作者JuBru
相关产品推荐
相关产品推荐

