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

如何让numpy.polyfit拟合季节性模型时避免周度拟合值跳变?

解决周度时间序列季节性拟合的首尾跳变问题

针对你用多项式拟合周度平均收益时出现的第52周与第1周跳变问题,以下是几种可行的解决方案:

方案1:带首尾相等约束的多项式拟合

numpy.polyfit是无约束最小二乘,要强制拟合曲线在x=1和x=52处值相等,可通过自定义约束的优化实现:

import numpy as np
from scipy.optimize import minimize

# 示例数据(替换为你的真实数据)
weeks = np.arange(1, 53)
avg_returns = np.random.randn(52)

# 定义多项式拟合的损失函数:拟合误差平方和
def poly_loss(coeffs, x, y):
    y_pred = np.polyval(coeffs, x)
    return np.sum((y_pred - y)**2)

# 定义约束条件:f(1) = f(52)
def continuity_constraint(coeffs):
    return np.polyval(coeffs, 1) - np.polyval(coeffs, 52)

# 用无约束拟合结果作为初始值
init_coeffs = np.polyfit(weeks, avg_returns, deg=3)

# 带约束的最小化求解
cons = {'type': 'eq', 'fun': continuity_constraint}
result = minimize(poly_loss, init_coeffs, args=(weeks, avg_returns), constraints=cons)
constrained_coeffs = result.x

# 生成平滑拟合曲线
fit_x = np.linspace(1, 52, 100)
fit_y = np.polyval(constrained_coeffs, fit_x)

方案2:使用周期性基函数(傅里叶级数)

多项式本身不具备周期性,改用正弦/余弦基函数的傅里叶拟合,天然满足首尾连续:

import numpy as np

weeks = np.arange(1, 53)
avg_returns = np.random.randn(52)

# 构造傅里叶基函数(可通过调整谐波数量控制平滑度)
def build_fourier_basis(x, n_harmonics):
    basis = np.zeros((len(x), 2*n_harmonics + 1))
    basis[:, 0] = 1  # 常数项
    for k in range(1, n_harmonics+1):
        basis[:, 2*k-1] = np.sin(2 * np.pi * k * x / 52)
        basis[:, 2*k] = np.cos(2 * np.pi * k * x / 52)
    return basis

# 选择2个谐波(可根据需求增减)
n_harmonics = 2
X = build_fourier_basis(weeks, n_harmonics)

# 最小二乘拟合
coeffs = np.linalg.lstsq(X, avg_returns, rcond=None)[0]

# 生成拟合曲线
fit_x = np.linspace(1, 52, 100)
fit_X = build_fourier_basis(fit_x, n_harmonics)
fit_y = fit_X @ coeffs

方案3:优化伪周扩展法

针对你之前的伪周扩展效果不佳的问题,可通过加权拟合提升原数据的权重:

import numpy as np

weeks = np.arange(1, 53)
avg_returns = np.random.randn(52)

# 扩展数据:前后各追加10周(原数据43-52周前置,1-10周后置)
extend_weeks = np.concatenate([np.arange(1-10, 1), weeks, np.arange(52+1, 52+11)])
extend_returns = np.concatenate([avg_returns[-10:], avg_returns, avg_returns[:10]])

# 加权拟合:原数据权重为1,扩展数据权重为0.5,降低扩展数据的影响
weights = np.concatenate([np.ones(10)*0.5, np.ones(52)*1, np.ones(10)*0.5])
coeffs = np.polyfit(extend_weeks, extend_returns, deg=3, w=weights)

# 生成1-52周的拟合曲线
fit_x = np.linspace(1, 52, 100)
fit_y = np.polyval(coeffs, fit_x)

方案4:周期性样条插值

使用三次周期性样条,直接强制首尾值和导数连续,彻底解决跳变:

import numpy as np
from scipy.interpolate import CubicSpline

weeks = np.arange(1, 53)
avg_returns = np.random.randn(52)

# 创建周期性三次样条
cs = CubicSpline(weeks, avg_returns, bc_type='periodic')

# 生成平滑曲线
fit_x = np.linspace(1, 52, 100)
fit_y = cs(fit_x)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 21:37:23