如何高效为Pandas DataFrame添加基于时间分组的Group_ID列?
高效为大型Pandas DataFrame添加分组ID列
需求描述
需要为大型Pandas DataFrame添加名为Group_ID的列,规则如下:
- 每个
Group_ID由Veh_ID和递增序号拼接而成(格式:Veh_ID_序号) - 同一
Veh_ID下,当相邻记录的Time差值大于5000时,递增序号加1,划分新组
原始数据示例
Time Time_slot Veh_ID Pwr 1 1 100 10 1 2 100 12 2 1 100 3 2 2 100 13 3 1 100 22 3 2 100 13 1 1 55 8 1 2 55 2 2 1 55 12 2 2 55 11 6000 1 100 7 6000 2 100 6 6001 1 100 11 6001 2 100 14 6001 1 55 7 6001 2 55 9 6002 1 55 9 6002 2 55 13 6003 1 55 10 6003 2 55 9
目标结果示例
Time Time_slot Veh_ID Pwr Group_ID 1 1 100 10 100_1 1 2 100 12 100_1 2 1 100 3 100_1 2 2 100 13 100_1 3 1 100 22 100_1 3 2 100 13 100_1 1 1 55 8 55_1 1 2 55 2 55_1 2 1 55 12 55_1 2 2 55 11 55_1 6000 1 100 7 100_2 6000 2 100 6 100_2 6001 1 100 11 100_2 6001 2 100 14 100_2 6001 1 55 7 55_2 6001 2 55 9 55_2 6002 1 55 9 55_2 6002 2 55 13 55_2 6003 1 55 10 55_2 6003 2 55 9 55_2
当前代码问题
用户尝试用循环实现,但代码复杂且触发SettingWithCopyWarning:
df.insert(loc = 4, column = 'Group_ID', value = 0) for v in df.Veh_ID.unique(): diffs = np.diff(df[df.Veh_ID == v].Time) change_indxs = np.where(diffs > 5000)[0] # Each location is the last of the group start_indx = df.index[0] last_indx = df.index[-1] abreak = last_indx for i, abreak in enumerate(change_indxs): aChunk = df.loc[start_indx:abreak+1] aChunk['Group_ID'].loc[start_indx:abreak+1] = str(v) + str(i)
错误信息:
SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame
高效解决方案
使用Pandas的向量化操作替代循环,既避免警告又大幅提升处理大型数据的效率:
实现代码
import pandas as pd # 1. 按Veh_ID分组,计算相邻Time的差值 df['time_diff'] = df.groupby('Veh_ID')['Time'].diff() # 2. 标记需要分组的边界(差值>5000的位置),首行填充False df['is_new_group'] = df['time_diff'] > 5000 df['is_new_group'] = df['is_new_group'].fillna(False) # 3. 按Veh_ID累计分组序号,首组序号为1 df['group_num'] = df.groupby('Veh_ID')['is_new_group'].cumsum() + 1 # 4. 拼接Veh_ID和分组序号得到Group_ID df['Group_ID'] = df['Veh_ID'].astype(str) + '_' + df['group_num'].astype(str) # 5. 清理临时列(可选,若不需要保留中间结果) df = df.drop(['time_diff', 'is_new_group', 'group_num'], axis=1)
代码解释
- 步骤1:通过
groupby('Veh_ID')['Time'].diff()计算每个车辆相邻记录的时间差,确保只在同一车辆内计算差值。 - 步骤2:标记时间差大于5000的位置为新组起点,首行因为没有前序记录,填充
False。 - 步骤3:按车辆累计新组标记的数量,加1后得到每组的序号(保证从1开始)。
- 步骤4:将车辆ID和分组序号转为字符串后拼接,得到最终的
Group_ID。 - 步骤5:删除临时列,保持DataFrame整洁。
这种方法完全避免了循环,利用Pandas的内置分组和向量化运算,处理大型数据集时效率远高于循环实现,同时不会触发SettingWithCopyWarning。
内容的提问来源于stack exchange,提问作者earnric
相关产品推荐
相关产品推荐

