Pandas groupby.diff问题:如何避免组间跨行计算差值
问题描述
我有一个已排序的Pandas DataFrame如下:
instrumentExtId Date proxyMethod isForceXS xsValue curveValue .ID1 2008-03-28 00:00:00 CrossSectional FALSE 6.86046681 6.86046681 .ID1 2008-03-31 00:00:00 CrossSectional FALSE 6.97468855 6.97468855 .ID1 2008-04-01 00:00:00 CrossSectional FALSE 6.83893432 6.83893432 .ID1 2008-04-02 00:00:00 CrossSectional FALSE 6.70250452 6.70250452 .ID2 2008-03-28 00:00:00 CrossSectional FALSE 3.10441877 3.10441877 .ID2 2008-03-31 00:00:00 CrossSectional FALSE 3.5104612 3.5104612 .ID2 2008-04-01 00:00:00 CrossSectional FALSE 3.52994089 3.52994089 .ID2 2008-04-02 00:00:00 CrossSectional FALSE 3.24236585 3.24236585
需求为:对每个instrumentExtId,先对xsValue和curveValue列应用反双曲正弦函数(np.arcsinh),再计算同ID内的日期间差值,同时保留proxyMethod和isForceXS列。
我编写了如下代码:
df = df.groupby(['instrumentExtId', 'Date', 'proxyMethod', 'isForceXS'], group_keys = True)[["xsValue","curveValue"]].\ apply(lambda x:np.arcsinh(x)). \ diff(). \ reset_index().\ drop(["level_4"], axis=1)
但运行结果中第二个ID的第一行,差值是该ID首行与前一个ID末行的计算结果,我期望此处为nan,请问问题出在哪里?
运行结果如下:
instrumentExtId Date proxyMethod isForceXS xsValue curveValue .ID1 2008-03-28 00:00:00 CrossSectional FALSE nan nan .ID1 2008-03-31 00:00:00 CrossSectional FALSE 0.016342295 0.016342295 .ID1 2008-04-01 00:00:00 CrossSectional FALSE -0.01945289 -0.01945289 .ID1 2008-04-02 00:00:00 CrossSectional FALSE -0.019934368 -0.019934368 .ID2 2008-03-28 00:00:00 CrossSectional FALSE -0.750188187 -0.75018818 .ID2 2008-03-31 00:00:00 CrossSectional FALSE 0.117631041 0.117631041 .ID2 2008-04-01 00:00:00 CrossSectional FALSE 0.005323083 0.005323083 .ID2 2008-04-02 00:00:00 CrossSectional FALSE -0.081488875 -0.081488875
问题原因与解决方法
问题根源
你的代码逻辑存在两个核心问题:
- 分组维度错误:你用
['instrumentExtId', 'Date', 'proxyMethod', 'isForceXS']分组,这会把每个**(ID+日期+proxyMethod+isForceXS)**组合拆成独立小组,apply(np.arcsinh)只是对单个小组的数值做转换,无法实现按ID批量处理。 - 全局计算差值:后续的
diff()是对整个DataFrame做全局差值计算,而非在每个instrumentExtId组内计算,导致.ID2的第一行会和.ID1的最后一行做差,而非保留nan。
正确实现代码
分步写法(更直观)
# 第一步:对目标列应用反双曲正弦函数 df[['xsValue', 'curveValue']] = np.arcsinh(df[['xsValue', 'curveValue']]) # 第二步:按instrumentExtId分组,在组内计算差值 df[['xsValue', 'curveValue']] = df.groupby('instrumentExtId')[['xsValue', 'curveValue']].diff()
链式写法(更简洁)
df = df.assign( xsValue=np.arcsinh(df['xsValue']), curveValue=np.arcsinh(df['curveValue']) ).groupby('instrumentExtId')[['xsValue', 'curveValue']].diff().assign( instrumentExtId=df['instrumentExtId'], Date=df['Date'], proxyMethod=df['proxyMethod'], isForceXS=df['isForceXS'] )[['instrumentExtId', 'Date', 'proxyMethod', 'isForceXS', 'xsValue', 'curveValue']]
以上两种写法都会让每个ID的首行差值为nan,后续行仅在同ID内计算日期间差值,完全符合需求。
内容的提问来源于stack exchange,提问作者Whitebeard13
相关产品推荐
相关产品推荐

