LSTM训练数据特征工程与优化实践
最近在做灵析项目的LSTM估值预测模型时,遇到了一个典型问题:模型训练完成后,准确率始终徘徊在43%左右。这个数字意味着模型的预测效果接近随机猜测,远远达不到可用的标准。
本文将记录完整的排查过程和优化路径,希望能为遇到类似问题的读者提供参考
一、问题现象
LSTM模型训练完成后,测试集准确率稳定在43%-45%之间,RMSE为21.14。无论调整LSTM层数、神经元数量,还是修改Dropout比例,效果都没有明显改善。
模型陷入了一个典型状态:参数调优无法突破性能瓶颈,说明问题不在模型结构本身。
二、排查过程
2.1 数据层面的检查
第一步是检查输入数据的质量。训练数据来自Tushare日线行情,包含收盘价、涨跌幅、成交量三个字段。这些字段本身是准确的,但问题在于它们全部是价格维度的数据。
模型只看到了“价格在涨跌”,却没有看到“估值在什么位置”。同样是10%的涨幅,PE=15和PE=45的含义完全不同,但模型无法区分这两种场景。
2.2 特征分析
为什么PE分位和PB分位是关键特征?因为估值分位回答了一个核心问题:当前价格在历史中处于什么位置。
在金融投资中,绝对的PE值参考意义有限,真正有价值的是“当前估值比过去70%的时间都贵”这种相对判断。模型缺少这个维度的信息,就无法理解估值周期的概念。
三、解决方案
3.1 特征扩展
将输入特征从1维扩展到5维:
| 特征类型 | 特征名称 | 说明 |
|---|---|---|
| 价格特征 | 收盘价 | 基础价格序列 |
| 量价特征 | 涨跌幅 | 价格变动幅度 |
| 量价特征 | 成交量 | 交易活跃度 |
| 估值特征 | PE分位 | 当前PE在历史中的位置 |
| 估值特征 | PB分位 | 当前PB在历史中的位置 |
核心改动是新增PE分位和PB分位两个估值特征:
# 计算单日估值分位
def calculate_pe_percentile(pe_value, pe_history):
return sum(1 for pe in pe_history if pe < pe_value) / len(pe_history)
3.2 重新训练
使用五维特征重新训练LSTM模型:
# 滑窗构造训练样本
def create_sequences(data, window=30, horizon=5):
X, y = [], []
for i in range(len(data) - window - horizon + 1):
X.append(data[i:i+window])
y.append(data[i+window:i+window+horizon])
return np.array(X), np.array(y)
训练完成后,评估指标出现明显变化:
RMSE: 21.14 → 14.56(下降31%) MAE: 6.37 → 5.48(下降14%)
四、总结
这次优化验证了一个判断:模型准确率上不去的根本原因往往不在模型结构,而在特征工程。
LSTM的结构没有变,参数没有变,变化的是输入特征。模型需要正确的信息才能做出正确的判断,而PE/PB分位就是这个场景下缺失的关键信息。
在尝试调参之前,值得先检查一个问题:模型是否拿到了所有必要的信息。有时候答案就在数据里,只是还没被喂给模型。
后续会加入其他特征继续把准确率提高

浙公网安备 33010602011771号