深度神经网络 (第六部分)。 神经网络分类器的融合: 引导聚合·综合运用
极限学习机集成的R回测与贝叶斯调参
这段 R 脚本用 elmNN 包搭了一个极限学习机(ELM)集成,再用贝叶斯优化搜参数。外汇与贵金属行情用这类集成做方向分类时,样本外表现仅具概率意义,实盘高风险,别直接当信号源。 集成训练部分先按 rng 种子循环生成 n 个 ELM 模型,每个都用 holdout 按 ratio=r/10 切训练集;预测阶段把 n 个模型输出按列合并成 y.pr,再以 0.5 为阈值转 0/1,算 F1 选前 (numEns*2+1) 个最优模型做平均集成。 直接跑 fitnes(numFeature=10, r=7, nh=5, fact=2) 在本地耗时约 7.86 秒(elapsed),得到的样本外 F1 为 0.761。 换 BayesianOptimization 搜参,init_points=10、n_iter=20、ucb 采集函数、kappa=2.576,第 23 轮摸到最优:numFeature=8、r=3、nh=3、fact=7,F1 抬到 0.777;历史前二组分别是 (8,3,3,7)→0.777 与 (8,1,5,7)→0.767。MT5 侧虽跑不了 R,但可把这套特征数=8、隐藏节点=3 的设定挪到自编 ELM 指标里对照品种波动率验证。
Ens <- foreach(i = class="num">1:n, .packages = "elmNN") %do% { rngtools::setRNG(rng[[k]]) idx <- rminer::holdout(Ytrain, ratio = r/class="num">10, mode = "random")$tr k <- k + class="num">1 elmtrain(x = Xtrain[idx, ], y = Ytrain[idx], nhid = nh, actfun = Fact[fact]) } setMKLthreads(class="num">2) #---predict--- Xtest <- X$train$x[ , bestF] foreach(i = class="num">1:n, .packages = "elmNN", .combine = "cbind") %do% { predict(Ens[[i]], newdata = Xtest) } -> y.pr #[ ,n] #---best--- foreach(i = class="num">1:n, .combine = "c") %do% { ifelse(y.pr[ ,i] > class="num">0.5, class="num">1, class="num">0) -> Ypred Evaluate(actual = Ytest, predicted = Ypred)$Metrics$F1 %>% mean() } -> Score Score %>% order(decreasing = TRUE) %>% head((numEns*class="num">2 + class="num">1)) -> bestNN #---test-aver-------- Xtest1 <- X$test$x[ , bestF] foreach(i = class="num">1:n, .packages = "elmNN", .combine = "+") %:% when(i %in% bestNN) %do% { predict(Ens[[i]], newdata = Xtest1)} %>% divide_by(length(bestNN)) -> ensPred ifelse(ensPred > class="num">0.5, class="num">1, class="num">0) -> ensPred Evaluate(actual = Ytest1, predicted = ensPred)$Metrics$F1 %>% mean() %>% round(class="num">3) -> Score class="kw">return(list(Score = Score, Pred = ensPred)) } }, env) #---------- evalq( system.time( res <- fitnes(numFeature = class="num">10, r = class="num">7, nh = class="num">5, fact = class="num">2) ) , env) user system elapsed class="num">8.65 class="num">0.19 class="num">7.86 > env$res$Score [class="num">1] class="num">0.761 #------ evalq( OPT_Res <- BayesianOptimization(fitnes, bounds = bonds, init_grid_dt = NULL, init_points = class="num">10, n_iter = class="num">20, acq = "ucb", kappa = class="num">2.576, eps = class="num">0.0, verbose = TRUE) , envir = env) Best Parameters Found: Round = class="num">23 numFeature = class="num">8.0000 r = class="num">3.0000 nh = class="num">3.0000 fact = class="num">7.0000 Value = class="num">0.7770 evalq({ OPT_Res %$% History %>% dplyr::arrange(desc(Value)) %>% head(class="num">10) %>% dplyr::select(-Round) -> best.init best.init }, env) numFeature r nh fact Value class="num">1 class="num">8 class="num">3 class="num">3 class="num">7 class="num">0.777 class="num">2 class="num">8 class="num">1 class="num">5 class="num">7 class="num">0.767
「集成模型在测试集上的衰减轨迹」
上面那组数字不是装饰,是某外汇品种特征筛选后逐轮训练集的规模与相关系数:第3轮 8/3/2/7 对应 0.760,到第10轮变成 11/2/24/4 对应 0.751,说明随着扰动样本放大,集成内单模型的相关性在缓慢走低。 这种走低不一定是好事——当第10轮出现 24 这个异常大的第三列值时,往往意味着某次 holdout 切分抽到了极端行情片段,外汇与贵金属的高波动特性会放大这类偏差。 下面这段 R 脚本做的是训练最优集成并做测试集平均预测,虽不是 MQL5 直接运行,但参数逻辑(numFeature=8、r=3、nh=3、fact=7)可直接映射到 MT5 特征工程的输入维度。 别把单次 F1 最高的模型当终局 代码里用 Score 排序取 head(numEns*2+1) 而不是只取 top1,是因为极端行情下单一 ELM 网容易过拟合;取 7 个做等权平均,测试集稳定性倾向更好,但回测收益仍可能随品种切换而漂移。
#--class="num">1-Train--optEns-predict--best--test-average------------------------ evalq({ Ytrain <- X$pretrain$y Ytest <- X$train$y Ytest1 <- X$test$y n <- class="num">500 numEns <- class="num">3 #--BestParams-------------------------- best.par <- OPT_Res$Best_Par %>% unname numFeature <- best.par[class="num">1] # 8L r <- best.par[class="num">2] # 3L nh <- best.par[class="num">3] # 3L fact <- best.par[class="num">4] # 7L bestF <- orderX %>% head(numFeature) Xtrain <- X$pretrain$x[ , bestF] setMKLthreads(class="num">1) k <- class="num">1 rng <- RNGseq(n, class="num">12345) #---train--- OptEns <- foreach(i = class="num">1:n, .packages = "elmNN") %do% { rngtools::setRNG(rng[[k]]) idx <- rminer::holdout(Ytrain, ratio = r/class="num">10, mode = "random")$tr k <- k + class="num">1 elmtrain(x = Xtrain[idx, ], y = Ytrain[idx], nhid = nh, actfun = Fact[fact]) } setMKLthreads(class="num">2) #---predict--- Xtest <- X$train$x[ , bestF] foreach(i = class="num">1:n, .packages = "elmNN", .combine = "cbind") %do% { predict(OptEns[[i]], newdata = Xtest) } -> y.pr #[ ,n] #---best--- foreach(i = class="num">1:n, .combine = "c") %do% { ifelse(y.pr[ ,i] > class="num">0.5, class="num">1, class="num">0) -> Ypred Evaluate(actual = Ytest, predicted = Ypred)$Metrics$F1 %>% mean() } -> Score Score %>% order(decreasing = TRUE) %>% head((numEns*class="num">2 + class="num">1)) -> bestNN #---test-aver-------- Xtest1 <- X$test$x[ , bestF] foreach(i = class="num">1:n, .packages = "elmNN", .combine = "+") %:% when(i %in% bestNN) %do% { predict(OptEns[[i]], newdata = Xtest1)} %>% divide_by(length(bestNN)) -> ensPred
◍ 集成模型在样本外集上的分类表现
把集成预测概率以 0.5 为阈值二值化后,在测试集 Ytest1 上跑混淆矩阵,整体准确率落在 0.778,Kappa 系数 0.5549,说明模型相较「无信息率 0.5269」的盲猜有实质提升,P 值小于 2e-16 基本排除了随机巧合。 分标签看,类 0 的精确率 0.751、召回 0.774、F1 0.762;类 1 的精确率 0.803、召回 0.782、F1 0.793。混淆矩阵里 178 例真 0 判对、212 例真 1 判对,误判各 52 与 59,两类错分较均衡。 最优神经网络的得分序列里,头部模型 Score 在 0.7099~0.7263 之间波动,bestNN 取最高 0.7263 那一只。外汇与贵金属行情受杠杆与跳空影响,这类统计优势只代表历史样本外概率倾向,实盘仍需以小仓位验证。
ifelse(ensPred > class="num">0.5, class="num">1, class="num">0) -> ensPred Evaluate(actual = Ytest1, predicted = ensPred)$Metrics[ ,class="num">2:class="num">5] %>% round(class="num">3) -> OptScore caret::confusionMatrix(Ytest1, ensPred) -> cm }, env) > env$Score[env$bestNN] [class="num">1] class="num">0.7262701 class="num">0.7220685 class="num">0.7144137 class="num">0.7129644 class="num">0.7126606 class="num">0.7101981 class="num">0.7099502 > env$OptScore Accuracy Precision Recall F1 class="num">0 class="num">0.778 class="num">0.751 class="num">0.774 class="num">0.762 class="num">1 class="num">0.778 class="num">0.803 class="num">0.782 class="num">0.793 > env$cm Confusion Matrix and Statistics Reference Prediction class="num">0 class="num">1 class="num">0 class="num">178 class="num">52 class="num">1 class="num">59 class="num">212 Accuracy : class="num">0.7784 class="num">95% CI : (class="num">0.7395, class="num">0.8141) No Information Rate : class="num">0.5269 P-Value [Acc > NIR] : <class="num">2e-16 Kappa : class="num">0.5549 Mcnemar&class="macro">#x27;s Test P-Value : class="num">0.569 Sensitivity : class="num">0.7511 Specificity : class="num">0.8030 Pos Pred Value : class="num">0.7739 Neg Pred Value : class="num">0.7823 Prevalence : class="num">0.4731 Detection Rate : class="num">0.3553 Detection Prevalence : class="num">0.4591 Balanced Accuracy : class="num">0.7770 &class="macro">#x27;Positive&class="macro">#x27; Class : class="num">0
融合分类器在 MT5 里的有效期与提升空间
ELM 神经网络组成的轻量融合分类器,分类品质已能逼近更复杂的 DNN,但真正值得在 MT5 里验证的是它的「保鲜期」。回测显示,训练后的融合在脱离训练集一半深度后仍能保持品质,最长可维持约 750 根柱线,而同条件下 DNN 只能撑到 250 根柱线。 单体分类器超参数优化把准确率拉到 Acc=0.77(95% 置信区间 0.73–0.81),多数表决与平均融合效果接近。若把连续预测值用校准或遗传搜索找最优截止阈值,品质还能再抬一截。 用可训练模型做合并器(堆叠)是下一步值得试的路线,可以是单个神经网络,也可以是神经网络的再融合。外汇与贵金属行情高风险,这类概率型信号只作辅助,实盘前请在 MT5 用历史数据跑一遍柱线衰减曲线。
「把这条线请下神坛」
随文打包的 GitHub/PartVI 里是六份 R 语言素材:函数集、训练测试脚本、超参优化脚本,外加两份环境清单和 ELM 文献压缩包。想在本地复现融合实验,先把 FUN_Ensemble.R 和 RUN_Ensemble.R 按顺序跑通,SessionInfo 文件能帮你对齐包版本,少踩依赖坑。 作者自己在评论区留过一组实测:10 个 DNN Darch 片段做平均融合, ensemble 的 osh=33%,反而略差于单模型最佳的 31%,最差误差 34%。结论很直白——融合不是万能膏药,对训练充分的强模型,简单平均常常不灵;它更适配 ELM 这类弱而不稳的网络。 外汇与贵金属市场高波动、高杠杆,任何模型融合方案都只是概率工具,实盘前请用 MT5 做历史回测与样本外验证。这条技术线值得玩,但别把它供成必胜法器。