pandas DataFrame按ID分组计算不同行列值差值的高效实现方法
问题描述
现有如下结构的pandas DataFrame:
Timestamp ID X X Diff Y Y Diff 0 0 100 1.728 None 14.378 None 1 12 100 2.035 None 14.378 None 2 24 100 2.342 None 14.378 None 3 36 100 2.630 None 14.378 None 4 48 100 2.937 None 14.416 None
需要计算相邻行的X、Y列值的差值,填入对应的X Diff和Y Diff列,最终效果如下:
Timestamp ID X X Diff Y Y Diff 0 0 100 1.728 None 14.378 None 1 12 100 2.035 0.307 14.378 0 2 24 100 2.342 0.307 14.378 0 3 36 100 2.630 0.288 14.378 0 4 48 100 2.937 0.307 14.416 0.038
计算规则:只有当前行与上一行ID相同时才计算差值,若为分组首行或相邻行ID不同,对应Diff列保留None。
目前已实现的for循环版本代码如下,在10万行以上数据量下运行效率极低:
def getDifferences(dataframe, column): for i in range(19): startValue = dataframe.iloc[i][column] endValue = dataframe.iloc[i+1][column] diff = endValue - startValue if column == "X": dataframe.at[i+1, "X Diff"] = diff else: dataframe.at[i+1, "Y Diff"] = diff
已知数据已清洗,每个ID固定对应20条连续记录,需要更优雅高效的实现方案。
解决方案
pandas自带的分组差分方法即可满足需求,完全不需要自定义循环,性能优异:
import pandas as pd # 按ID分组后对指定列计算相邻行差值 df['X Diff'] = df.groupby('ID')['X'].diff() df['Y Diff'] = df.groupby('ID')['Y'].diff() # 若需要将默认的NaN替换为None,执行以下代码即可 df = df.where(pd.notnull(df), None)
说明:
- 该实现是向量化运算,底层为C语言实现,10万行数据处理耗时仅为毫秒级,远快于Python层的for循环实现
- groupby操作保证差值计算仅在同ID分组内执行,不会出现跨ID计算的问题,天然符合需求规则
- 每个分组的第一行没有前序行,diff方法会自动返回空值,和需求的首行保留None的要求一致
如果需要更极致的性能,也可以使用纯numpy实现,跳过groupby的分组开销:
import numpy as np x = df['X'].values y = df['Y'].values ids = df['ID'].values # 计算X差值,非连续ID位置设为空 x_diff = np.concatenate([[np.nan], x[1:] - x[:-1]]) x_diff[ids[1:] != ids[:-1]] = np.nan df['X Diff'] = x_diff # 计算Y差值,非连续ID位置设为空 y_diff = np.concatenate([[np.nan], y[1:] - y[:-1]]) y_diff[ids[1:] != ids[:-1]] = np.nan df['Y Diff'] = y_diff # 可选替换NaN为None df = df.where(pd.notnull(df), None)
内容的提问来源于stack exchange,提问作者studenprogrammer
相关产品推荐
相关产品推荐

