You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Pandas仅在有效数据区间计算pct_change且保留完整索引?

解决Pandas中pct_change在NaN区域无效计算的问题

问题场景

现有带时间索引的DataFrame,部分行存在NaN值,且索引超出最后一个有效数据点:

2022-01-31  96.210  21649.6
2022-02-28  96.390  21708.4
2022-03-31  97.410  21739.7
2022-04-30  98.630  21644.3
2022-05-31  103.744 21649.2
2022-06-30  102.498 21607.4
2022-07-31  105.138 21636.1
2022-08-31  105.450 21631.8
2022-09-30  109.691 21503.1
2022-10-31  111.745 21414.8
2022-11-30  111.481 21351.6
2022-12-31  104.728 NaN
2023-01-31  103.522 NaN
2023-02-28  NaN
2023-03-31  NaN
2023-04-30  NaN
2023-05-31  NaN
2023-06-30  NaN 
2023-07-31  NaN 
2023-08-31  NaN

计算pct_change(12)时,Pandas会在最后一个有效数据点之后继续计算(将NaN视为参与计算的有效值),导致结果不符合预期。需要实现:

  • 保留所有原始索引
  • 仅在每列的非NaN有效范围内计算pct_change
  • 无需手动指定索引范围,自动适配后续新增数据
  • 不能使用dropna方法

解决方案

方法1:基于最后有效索引过滤结果

先正常计算pct_change,再通过每列的最后有效索引,将该索引之后的结果设为NaN:

import pandas as pd
import numpy as np

# 构造示例DataFrame(实际使用时替换为你的数据)
data = {
    'col1': [96.210, 96.390, 97.410, 98.630, 103.744, 102.498, 105.138, 105.450, 109.691, 111.745, 111.481, 104.728, 103.522, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan],
    'col2': [21649.6, 21708.4, 21739.7, 21644.3, 21649.2, 21607.4, 21636.1, 21631.8, 21503.1, 21414.8, 21351.6, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan]
}
index = pd.date_range(start='2022-01-31', end='2023-08-31', freq='M')
df = pd.DataFrame(data, index=index)

# 计算百分比变化
pct_result = df.pct_change(12)

# 获取每列最后一个非NaN值的索引
last_valid_indices = df.apply(lambda col: col.last_valid_index())

# 遍历每列,将最后有效索引之后的结果设为NaN
for col, idx in last_valid_indices.items():
    if idx is not None:
        # 找到最后有效索引的下一个月份,之后的行全部设为NaN
        next_month = idx + pd.DateOffset(months=1)
        pct_result.loc[next_month:, col] = np.nan

print(pct_result)

方法2:基于有效范围掩码过滤

通过生成布尔掩码标记每列的有效数据范围(从第一个非NaN到最后一个非NaN),再用掩码过滤pct_change结果:

import pandas as pd
import numpy as np

# 构造示例DataFrame(实际使用时替换为你的数据)
data = {
    'col1': [96.210, 96.390, 97.410, 98.630, 103.744, 102.498, 105.138, 105.450, 109.691, 111.745, 111.481, 104.728, 103.522, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan],
    'col2': [21649.6, 21708.4, 21739.7, 21644.3, 21649.2, 21607.4, 21636.1, 21631.8, 21503.1, 21414.8, 21351.6, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan]
}
index = pd.date_range(start='2022-01-31', end='2023-08-31', freq='M')
df = pd.DataFrame(data, index=index)

# 生成有效范围掩码:标记每列从第一个非NaN到最后一个非NaN的行
# 从顶部向下累积标记有效行
top_mask = df.notna().cummax(axis=0)
# 从底部向上累积标记有效行,再反转回来
bottom_mask = df.notna()[::-1].cummax(axis=0)[::-1]
# 两者取交集得到最终有效掩码
valid_mask = top_mask & bottom_mask

# 用掩码过滤pct_change结果,无效区域设为NaN
pct_result = df.pct_change(12).where(valid_mask)

print(pct_result)

效果验证

两种方法都能得到预期结果:

2022-01-31  0.069713    0.117543
2022-02-28  0.059464    0.106713
2022-03-31  0.069969    0.094989
2022-04-30  0.061336    0.076258
2022-05-31  0.140671    0.060263
2022-06-30  0.141022    0.056075
2022-07-31  0.135400    0.049517
2022-08-31  0.145573    0.038228
2022-09-30  0.186490    0.025632
2022-10-31  0.188271    0.012812
2022-11-30  0.187484    0.000112
2022-12-31  0.090576    NaN
2023-01-31  0.076000    NaN
2023-02-28  NaN         NaN
2023-03-31  NaN         NaN
2023-04-30  NaN         NaN
2023-05-31  NaN         NaN
2023-06-30  NaN         NaN
2023-07-31  NaN         NaN
2023-08-31  NaN         NaN 

内容的提问来源于stack exchange,提问作者user20856754

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 07:50:25