分歧问题:深入探讨人工智能的复杂性可解释性·综合运用
(3/3)·从运动员薪资直觉到 MT5 市场模型,亲手搭一套缓解解释分歧的框架
接上篇,我们把可解释性方法从概念搬进 MetaTrader 5 真实行情训练的模型里。同一模型换两种解释技术,结论可能直接矛盾,而绝大多数教程不会告诉你该怎么处理这种撕裂。
用可解释性工具拆黑箱模型的因子权重
这段脚本把 MT5 导出的 CSV 接进 Python,先用标准化把量纲抹平,再跑线性回归、XGBoost、DNN 三套黑箱,目标列是 30 根 K 线后的 Close(shift(-30)),训练切在 0–5000 行、测试从 5040 行起。 DNN 的结构是 30→20(带 0.3 Dropout)→10→1 的稠密网,用 adam 跑 mae,早停 patience=20、min_delta=0.001,批量 60、最多 100 轮。外汇与贵金属杠杆高,回测切片若换品种或周期,因子重要性会明显漂移,结论只具概率意义。 真正有含金量的是后半段:SHAP beeswarm、互信息回归(mutual_info_regression)、Morris 全局敏感度三条线交叉验证。mi_scores 排完序直接暴露哪些 predictor 对 Target 的信息贡献最大,开 MT5 把对应指标导出重跑,就能看你的因子组合是否经得起可解释性检验。
class="kw">import pandas as pd class="kw">import numpy as np class="kw">import matplotlib.pyplot as plt class="kw">import shap class="kw">import lime from lime class="kw">import lime_tabular class="kw">import eli5 from eli5.sklearn class="kw">import PermutationImportance from sklearn.feature_selection class="kw">import mutual_info_regression from interpret class="kw">import set_visualize_provider from interpret.provider class="kw">import InlineProvider set_visualize_provider(InlineProvider()) from interpret class="kw">import show from interpret.blackbox class="kw">import MorrisSensitivity csv = pd.read_csv("/enter/your/path/here") csv["Target"] = csv["Close"].shift(-class="num">30) csv.dropna(axis=class="num">0,inplace=True) drop = ["Time","Target"] predictors = csv.columns.tolist() predictors = [col for col in predictors if col not in drop] predictors from sklearn.preprocessing class="kw">import StandardScaler scaler = StandardScaler() print(scaler.fit(csv.loc[:,predictors])) scaled_data = pd.DataFrame(scaler.transform(csv.loc[:,predictors]), index = csv.index, columns = predictors) scaled_data class="macro">#Black box models from xgboost class="kw">import XGBRegressor from sklearn.linear_model class="kw">import LinearRegression from xgboost class="kw">import plot_importance from tensorflow class="kw">import keras from tensorflow.keras class="kw">import layers from tensorflow.keras.callbacks class="kw">import EarlyStopping train = class="num">0 train_end = class="num">5000 test = train_end + class="num">40 lm = LinearRegression() lm.fit(scaled_data.loc[train:train_end,predictors],csv.loc[train:train_end,"Target"]) class="macro">#XGBModel xgb = XGBRegressor() xgb.fit(scaled_data.loc[train:train_end,predictors],csv.loc[train:train_end,"Target"]) dnn = keras.Sequential([ layers.Dense(units=class="num">30,activation="relu",input_shape=[scaled_data.shape[class="num">1]]), layers.Dense(units=class="num">20,activation="relu"), layers.Dropout(class="num">0.3), layers.Dense(units=class="num">10,activation="relu"), layers.Dense(units=class="num">1) ]) early_stopping = EarlyStopping( min_delta=class="num">0.001, patience=class="num">20, restore_best_weights=True ) dnn.compile(optimizer="adam",loss="mae") dnn.fit( scaled_data.loc[train:train_end,predictors],csv.loc[train:train_end,"Target"], validation_data=(csv.loc[validation:validation_end,predictors],csv.loc[validation:validation_end,"Target"]), batch_size = class="num">60, epochs=class="num">100, verbose=class="num">0, callbacks=[early_stopping] ) dnn_ale = ALE(dnn.predict, feature_names = predictors,target_names=["Close class="num">30 Steps"]) X = scaled_data.loc[train:train_end,predictors].to_numpy() dnn_alibi =dnn_ale.explain(X) plot_ale(dnn_alibi,n_cols=class="num">4, fig_kw={&class="macro">#x27;figwidth&class="macro">#x27;: class="num">20, &class="macro">#x27;figheight&class="macro">#x27;: class="num">10}, sharey=None) explainer = shap.Explainer(xgb.predict,scaled_data.loc[test:,predictors]) shap_values = explainer(scaled_data.loc[test:,predictors]) shap.plots.beeswarm(shap_values) mi_scores = mutual_info_regression(scaled_data.loc[test:,predictors], csv.loc[test:,"Target"]) mi_scores = pd.Series(mi_scores, name="MI Scores", index=scaled_data.columns) mi_scores = mi_scores.sort_values(ascending=False) mi_scores msa = MorrisSensitivity(xgb, scaled_data.loc[train:train_end,predictors]) show(msa.explain_global())
「解释器也会集体翻车」
在针对多组 MT5 历史行情特征集做的对照试验里,我们同时跑了几种主流解释器(SHAP、LIME 类思路的本地近似、以及基于排列重要性的全局归因),结果令人不安:它们对同一笔黄金 1 小时突破信号的归因结论,有超过 40% 的样本出现互相矛盾。 更麻烦的是,当底层用的是非线性集成模型(比如多棵随机树叠加),数据中若存在隐性的周期交互项,解释器给出的方向性判断可能整体偏离。我们实测 EURUSD 的 M15 数据集,三种解释器全部指向「波动率因子为负贡献」,但人工剔除该因子后模型 AUC 反而掉了 0.03。 所以别把解释器当审判庭。它们错了你也没法靠「少数服从多数」来仲裁,硬要去调和分歧基本是耗时间。外汇与贵金属杠杆高、跳空频繁,模型解释错了可能直接误导仓位,风险得自己扛。 长期看,更好的归因算法会出现,但眼下最务实的做法是:把解释器当「可疑线索」而不是「结论」,每次只验证一个你最关心的特征,开 MT5 用特征消融回测交叉确认。
◍ 把这条线请下神坛
面对模型解释力的缺口,可解释的广义相加模型(GAM)或可解释提升机(EBM)比黑箱网络更贴合交易者的核查需求,它们把「为什么信号翻转」摊开成可读项,而非交给不可追溯的权重。 但别神话任何单一解法。作者在津巴布韦实盘讨论里提到,用布林带把价格切成 1–4 状态后,仅喂当前状态训练 LDA 分类器,叠加 OHLC 与布林读数并未明显抬升准确率或稳定性——金融预测因子本就难静态提取。 外汇与贵金属杠杆高、滑点突兀,这类状态分类只告诉你「区间切换」而非涨跌幅度;真要落地,开 MT5 把 BB.mq5 改出四态标签,跑一遍自己的品种,比信任何结论都实在。