如何在Pandas中不创建新DataFrame实现按ID分组计算指定条件下的时间差
Pandas按ID分组计算指定行的时间差(无需创建新DataFrame)
需求说明
按ID字段分组,仅针对Condition>0的行,计算该行与下一行的Time字段时间差(单位:秒),要求不额外创建新的DataFrame(比如原实现里的df2)。
输入数据集
import pandas as pd data = { 'ID': [1, 1, 1, 1, 2, 2, 2], 'Time': ['2023-10-01 08:00:00', '2023-10-01 08:00:10', '2023-10-01 08:00:25', '2023-10-01 08:00:30', '2023-10-01 09:00:00', '2023-10-01 09:00:05', '2023-10-01 09:00:15'], 'Condition': [1, 0, 1, 1, 1, 1, 0] } df = pd.DataFrame(data) df['Time'] = pd.to_datetime(df['Time'])
原实现代码(需优化)
原代码通过创建新DataFrame处理,不符合需求:
# 原实现:额外创建了df2 df2 = df[df['Condition'] > 0].copy() df2['Time_Diff'] = df2.groupby('ID')['Time'].diff(-1).dt.total_seconds().abs()
优化后的实现(无需创建新DataFrame)
方式1:分组遍历实现(易理解)
# 先给原DataFrame新增空列存结果 df['Time_Diff'] = None # 按ID分组处理每个组 for id_group, group in df.groupby('ID'): # 筛选组内Condition>0的行的索引 valid_rows_idx = group[group['Condition'] > 0].index # 计算这些行与下一行的时间差(转成秒数,取绝对值避免负数) time_diff_values = group.loc[valid_rows_idx, 'Time'].diff(-1).dt.total_seconds().abs() # 把结果直接填回原DataFrame对应位置 df.loc[valid_rows_idx, 'Time_Diff'] = time_diff_values # 可选:把结果转为数值类型 df['Time_Diff'] = pd.to_numeric(df['Time_Diff'])
方式2:向量化实现(更高效)
# 直接在原DataFrame上完成所有操作,无需循环 df['Time_Diff'] = ( df.groupby('ID')['Time'] .apply(lambda x: x.where(df.loc[x.index, 'Condition'] > 0).diff(-1).dt.total_seconds().abs()) )
预期输出
ID Time Condition Time_Diff 0 1 2023-10-01 08:00:00 1 25.0 1 1 2023-10-01 08:00:10 0 NaN 2 1 2023-10-01 08:00:25 1 5.0 3 1 2023-10-01 08:00:30 1 NaN 4 2 2023-10-01 09:00:00 1 5.0 5 2 2023-10-01 09:00:05 1 NaN 6 2 2023-10-01 09:00:15 0 NaN
代码说明
- 向量化方式里,
groupby('ID')['Time'].apply(...)对每个ID组单独处理;x.where(...)只保留组内Condition>0的行的时间值,其余设为NaN; diff(-1)是计算当前行与下一行的时间差(默认方向是当前减下一行,所以用abs()转成正的秒数);- 两种方式都是直接在原DataFrame上赋值结果,完全不需要额外创建新的DataFrame。
内容的提问来源于stack exchange,提问作者Sangeetha R
相关产品推荐
相关产品推荐

