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

Python如何正确拼接滚动回归结果 修复concat产生NaN值问题

滚动OLS回归结果DataFrame拼接异常修复

问题场景

针对全量股票ticker逐标的计算滚动窗口下的OLS回归Beta系数、标准误,循环内单ticker结果生成后直接纵向拼接至总结果表,最终输出表存在大量空值:同一滚动窗口截止日期对应多行,每行仅存储单个ticker的计算结果,其余列均为NaN,无法得到单窗口单行、各列存储不同ticker指标的宽表结构。

错误实现代码

import pandas as pd
import numpy as np
import statsmodels.api as sm

# 模拟基础数据:日频收益率,索引为交易日期,列为各股票ticker
np.random.seed(42)
trade_dates = pd.date_range(start='2023-01-01', periods=200, freq='B')
ticker_list = ['AAPL', 'MSFT', 'GOOG']
stock_ret = pd.DataFrame(
    np.random.randn(200, 3)/100,
    index=trade_dates,
    columns=ticker_list
)
mkt_ret = pd.Series(
    np.random.randn(200)/100,
    index=trade_dates,
    name='market_ret'
)
roll_window = 60

# 错误拼接逻辑
final_result = pd.DataFrame()
for ticker in ticker_list:
    ticker_calc_res = []
    # 逐滚动窗口计算回归指标
    for idx in range(roll_window, len(stock_ret)+1):
        win_stock = stock_ret[ticker].iloc[idx-roll_window:idx]
        win_mkt = mkt_ret.iloc[idx-roll_window:idx]
        ols_model = sm.OLS(win_stock, sm.add_constant(win_mkt)).fit()
        ticker_calc_res.append({
            'date': stock_ret.index[idx-1],
            f'{ticker}_beta': ols_model.params['market_ret'],
            f'{ticker}_se': ols_model.bse['market_ret']
        })
    ticker_df = pd.DataFrame(ticker_calc_res).set_index('date')
    # 错误点:默认沿纵向axis=0拼接
    final_result = pd.concat([final_result, ticker_df], axis=0)

异常输出特征

输出表总长度为 ticker数量 * 有效滚动窗口数,同一日期重复出现多次,非当前循环ticker的字段全部为NaN,样例如下:

dateAAPL_betaAAPL_seMSFT_betaMSFT_seGOOG_betaGOOG_se
2023-03-280.1240.089NaNNaNNaNNaN
2023-03-290.1170.091NaNNaNNaNNaN
2023-03-28NaNNaN-0.0720.103NaNNaN
2023-03-29NaNNaN-0.0680.102NaNNaN
2023-03-28NaNNaNNaNNaN0.0950.078
2023-03-29NaNNaNNaNNaN0.0970.077

异常原因:单ticker结果表以日期为索引,不同ticker的结果列名完全不重叠,纵向拼接会按行堆叠,缺失列自动填充NaN。

修复方案

调整拼接逻辑,先将所有单ticker结果存入列表,最终沿横向axis=1按日期索引对齐拼接,自动匹配同一窗口日期下不同ticker的计算值。
修复后可直接运行的代码如下:

final_result = []
for ticker in ticker_list:
    ticker_calc_res = []
    for idx in range(roll_window, len(stock_ret)+1):
        win_stock = stock_ret[ticker].iloc[idx-roll_window:idx]
        win_mkt = mkt_ret.iloc[idx-roll_window:idx]
        ols_model = sm.OLS(win_stock, sm.add_constant(win_mkt)).fit()
        ticker_calc_res.append({
            'date': stock_ret.index[idx-1],
            f'{ticker}_beta': ols_model.params['market_ret'],
            f'{ticker}_se': ols_model.bse['market_ret']
        })
    ticker_df = pd.DataFrame(ticker_calc_res).set_index('date')
    final_result.append(ticker_df)

# 修正点:沿横向axis=1按索引对齐拼接
final_result = pd.concat(final_result, axis=1).reset_index()

修复后验证

输出表总长度等于有效滚动窗口数,同一日期仅对应单行,所有ticker的指标按列填充无空值,符合预期宽表结构:

dateAAPL_betaAAPL_seMSFT_betaMSFT_seGOOG_betaGOOG_se
2023-03-280.1240.089-0.0720.1030.0950.078
2023-03-290.1170.091-0.0680.1020.0970.077

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 02:18:19