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

如何在Pandas滚动计算中排除NaN,取最近10个有效值的均值

解决方案:基于最近10个有效值的滚动平均

你的核心需求是忽略NaN,取当前位置之前的最近10个有效值计算平均,原rolling(10)的问题在于它是按固定行数窗口计算,而非按有效值数量,所以无法满足需求。以下是两种可行方案:

方案一:高效向量化实现(适合大数据量)

利用merge_asof实现跨多行匹配最近的10个有效值,避免逐行循环的性能损耗:

import pandas as pd

# 1. 提取所有有效值及其原始索引,并生成序号
valid_df = df[df['AST_Hit'].notna()].reset_index().rename(columns={'index': 'valid_index'})
valid_df['seq'] = valid_df.index + 1  # 为每个有效值分配递增序号

# 2. 计算每个有效值对应的前10个有效值的平均(shift(1)排除当前值)
valid_df['rolling_10_mean'] = valid_df['AST_Hit'].rolling(window=10, min_periods=10).mean().shift(1)

# 3. 将结果匹配回原DataFrame的所有行
all_indices = df.reset_index()[['index']].sort_values('index')
result = pd.merge_asof(
    all_indices,
    valid_df[['valid_index', 'rolling_10_mean']].sort_values('valid_index'),
    left_on='index',
    right_on='valid_index',
    direction='backward'  # 匹配当前索引之前最近的有效值结果
)

# 4. 将最终结果合并到原DataFrame
df['rolling_10_valid_mean'] = result.set_index('index')['rolling_10_mean']

方案二:逐行自定义计算(适合小数据量,逻辑直观)

如果数据量不大,可直接通过apply实现逻辑,更易理解:

import pandas as pd
import numpy as np

# 提取所有有效值及其索引
valid_vals = df['AST_Hit'].dropna()

def calc_last_10_mean(current_idx):
    # 筛选当前索引之前的所有有效值
    prior_vals = valid_vals[valid_vals.index < current_idx]
    # 取最后10个,不足10个返回NaN
    if len(prior_vals) < 10:
        return np.nan
    return prior_vals.tail(10).mean()

# 应用到每个行索引
df['rolling_10_valid_mean'] = df.index.map(calc_last_10_mean)

关键说明

  • 原代码问题:rolling(10)是固定行数窗口,哪怕窗口内有效值不足10个也会计算平均,且无法跨窗口去补够10个有效值;min_periods仅控制窗口内最少需要多少有效值才输出结果,无法改变窗口的行数限制。
  • 不建议删除NaN行:删除会破坏原DataFrame的索引结构,丢失NaN行对应的其他列数据,对于大数据量来说也没必要做额外的数据清理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 18:57:06