如何在Pandas DataFrame中计算当前值与历史最大值的涨跌幅(不含当前行)
解决Pandas中计算当前值相对于之前所有行最大值的百分比变化问题
简洁解决方案
你需要计算的是当前值相对于截至上一行的Value列最大值的百分比变化,同时保留NaN行的空值。可以通过以下简洁代码实现:
import pandas as pd import numpy as np # 初始化DataFrame df = pd.DataFrame({'Value': [1000, 1100, np.nan, 1050, 990, np.nan, 1200, np.nan, 1150, 1300]}) # 计算截至上一行的累积最大值,第一行用自身值作为参考 cum_max = df['Value'].cummax() prev_max = cum_max.shift(1).fillna(df['Value'].iloc[0]) # 计算百分比变化,仅对非NaN行计算,NaN行保留空值 df['mdd/mru'] = np.where( df['Value'].notna(), (df['Value'] - prev_max) / prev_max, np.nan ).round(4) print(df)
执行后得到的结果与你的期望完全匹配:
Value mdd/mru 0 1000.0 0.0000 1 1100.0 0.1000 2 NaN NaN 3 1050.0 -0.0455 4 990.0 -0.1000 5 NaN NaN 6 1200.0 0.0909 7 NaN NaN 8 1150.0 -0.0417 9 1300.0 0.0833
关键逻辑说明
cum_max = df['Value'].cummax():先计算包含当前行的累积最大值,自动忽略NaN,确保能追踪到历史所有行的最大值。prev_max = cum_max.shift(1).fillna(df['Value'].iloc[0]):将累积最大值整体下移一行,得到截至上一行的最大值;第一行下移后为NaN,替换为自身值,保证第一行计算结果为0。np.where(...):只对Value非空的行计算百分比变化,空值行直接保留NaN,避免额外的替换操作。.round(4):将结果保留四位小数,与你的期望格式一致。
为什么之前的方法不生效
- 直接使用
df['Value'].cummax()会将当前行纳入最大值计算,导致新的最大值行结果为0,不符合需求。 - 单纯
shift(1).cummax()会因为中间的NaN导致部分行的历史最大值丢失,出现无意义的NaN结果。 - 填充NaN为0会错误地将0纳入最大值计算,导致后续行的百分比变化结果失真。
内容的提问来源于stack exchange,提问作者rose_1
相关产品推荐
相关产品推荐

