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

基于SB3 DQN的股票数据训练:观测值缩放技术问询

股票DQN训练中的数据缩放问题解答

问题1:仅对当前观测值(120根K线)做MinMaxScaler缩放是否正确?

你当前的做法是错误的。你的scale_data函数每次都对输入的120根K线数据调用fit_transform,这会导致每次拟合的scaler基准(min/max)都不一样——因为每段120根K线的价格、RSI等特征的波动范围都有差异。这样训练出来的模型学到的特征分布是不稳定的,无法适配全局的数据规律,最终会严重影响模型的泛化能力。

正确的做法是:

  • 先用全部20万行5分钟K线数据中的数值特征(开盘价、最高价、最低价、收盘价、RSI、成交量)来拟合MinMaxScaler,只做一次fit;
  • 之后在训练阶段,对每个观测值(120根K线)只调用transform,用预拟合好的scaler进行缩放;
  • 时间特征(小时、分钟、星期几)属于周期性特征,不需要用MinMaxScaler,建议用正弦/余弦编码转换成周期性特征(比如hour_sin = sin(2π*hour/23)),或者直接归一化到0-1也可以,但不要参与scaler的拟合。

修正后的scale_data逻辑示例(提前拟合好scaler):

# 训练前提前用全量数据拟合scaler
import numpy as np
from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler()
# full_data是你的20万行全量K线数据
scaler.fit(full_data[['OPEN', 'HIGH', 'LOW', 'CLOSE', 'rsi', 'TICKVOL']])

# 自定义Gym环境中的scale_data函数
def scale_data(self, obs):
    df1 = obs.copy()  # 避免修改原观测数据
    # 用预拟合的scaler做转换,不再重新fit
    df1[['OPEN', 'HIGH', 'LOW', 'CLOSE', 'rsi', 'TICKVOL']] = scaler.transform(
        obs[['OPEN', 'HIGH', 'LOW', 'CLOSE', 'rsi', 'TICKVOL']])
    # 保留时间特征,可选做周期编码优化
    df1['HOUR_SIN'] = np.sin(2 * np.pi * df1['HOUR'] / 23)
    df1['HOUR_COS'] = np.cos(2 * np.pi * df1['HOUR'] / 23)
    df1['MINUTE_SIN'] = np.sin(2 * np.pi * df1['MINUTE'] / 59)
    df1['MINUTE_COS'] = np.cos(2 * np.pi * df1['MINUTE'] / 59)
    # 删除原始时间列,用编码后的特征替代
    df1.drop(['HOUR', 'MINUTE'], axis=1, inplace=True)
    return df1.values

问题2:预测阶段如何处理缩放?

预测阶段的核心是复用训练前拟合好的scaler,步骤如下:

  1. 训练完成后,把拟合好的scaler保存到本地(用joblib或pickle):
import joblib
joblib.dump(scaler, 'stock_scaler.pkl')
  1. 预测时,先加载这个保存好的scaler,然后对最近120根K线的数值特征调用transform,绝对不能再调用fit:
# 预测时加载预拟合的scaler
scaler = joblib.load('stock_scaler.pkl')

# 处理预测用的120根K线数据,逻辑和训练时完全一致
def predict_scale_data(obs):
    df1 = obs.copy()
    df1[['OPEN', 'HIGH', 'LOW', 'CLOSE', 'rsi', 'TICKVOL']] = scaler.transform(
        obs[['OPEN', 'HIGH', 'LOW', 'CLOSE', 'rsi', 'TICKVOL']])
    # 时间特征处理和训练阶段保持统一
    df1['HOUR_SIN'] = np.sin(2 * np.pi * df1['HOUR'] / 23)
    df1['HOUR_COS'] = np.cos(2 * np.pi * df1['HOUR'] / 23)
    df1['MINUTE_SIN'] = np.sin(2 * np.pi * df1['MINUTE'] / 59)
    df1['MINUTE_COS'] = np.cos(2 * np.pi * df1['MINUTE'] / 59)
    df1.drop(['HOUR', 'MINUTE'], axis=1, inplace=True)
    return df1.values

这样就能保证预测时的缩放基准和训练时完全一致,不会出现缩放结果差异的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 22:23:12