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

股票成交量突破计算异常:Python rolling均值返回NaN,结果全为No

问题分析

你的代码问题核心出在两个点:

  1. Rolling窗口逻辑与Excel不匹配:Excel公式里用的是当日之前21天的成交量平均值(I3:I24是I2的前21行,不含当日),但Pandas默认的rolling(window=21).mean()是包含当前行在内的21行数据的平均值;如果你的日期数据是从新到旧排序的,rolling的计算方向会完全颠倒。
  2. NaN值的成因:average_volume全为NaN,要么是VOLUME列本身有大量缺失值,要么是数据排序错误导致rolling窗口无法获取有效历史数据。
解决方案

步骤1:确保数据按日期从旧到新排序

先检查并修正日期列的排序(假设日期列名为DATE):

# 转换日期列为datetime类型(若未转换)
df['DATE'] = pd.to_datetime(df['DATE'])
# 按日期从旧到新排序,重置索引
df = df.sort_values('DATE').reset_index(drop=True)

步骤2:修正Rolling平均值计算逻辑

要实现Excel中“过去21日(不含当日)平均值”的逻辑,需用shift(1)将rolling结果偏移一行,对应取当前行之前的21天数据:

import pandas as pd
import numpy as np

def add_vol_breakout_column(self, df):
    # 确保日期排序正确
    df['DATE'] = pd.to_datetime(df['DATE'])
    df = df.sort_values('DATE').reset_index(drop=True)
    
    # 计算过去21日(不含当日)的成交量平均值
    # rolling(21)取当前行及前20行,shift(1)后变为当前行之前的完整21行数据
    average_volume = df['VOLUME'].rolling(window=21).mean().shift(1)
    
    # 处理前21行的NaN(无足够历史数据,默认标记为No)
    volume_breakout = df['VOLUME'] > (average_volume * 3)
    df['VolBrkOut'] = np.where(volume_breakout.fillna(False), 'Yes', 'No')
    
    print(f"Updated DataFrame:\n{df}")
    return df

步骤3:排查VOLUME列缺失值

若仍出现大量NaN,先检查成交量列的缺失情况:

print("VOLUME列缺失值数量:", df['VOLUME'].isna().sum())

如果有缺失值,可选择填充或删除缺失行:

# 用0填充缺失值
df['VOLUME'] = df['VOLUME'].fillna(0)
# 或删除包含缺失值的行
df = df.dropna(subset=['VOLUME'])
逻辑验证

修改后,第22行(索引21)的VolBrkOut计算逻辑,完全对应Excel公式=IF(I22>(AVERAGE(I1:I21)*3),"Yes","No")的逻辑,和你最初的需求一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 08:47:31