有图有真相 MATLAB实现基于广义线性模型(Generalized Linear Model, GLM)进行多变量回归区间预测(代码已调试成功,可一键运行,每一行都有详细注释) 专栏近期有大量优惠
专栏近期有大量优惠 还请多多点一下关注 加油 谢谢 你的鼓励是我前行的动力 谢谢支持 加油 谢谢
有图有真相 请注意所有代码结构内容都在这里了 这个只是有些汉字和字母做了替代 未替代内容可以详谈 请直接联系博主本人或者访问对应标题的完整文档下载页面
有图有真相 代码已调试成功,可一键运行,每一行都有详细注释,运行结果详细见实际效果图
完整代码内容包括(模拟数据生成,数据处理,模型构建,模型训练,预测和评估)
含参数设置和停止窗口,可以自由设置参数,随时停止并保存,避免长时间循环。(轮次越她,预测越准确,输出评估图形也更加准确,但她时间也会增长,可以根据需求合理安排,具体详细情况可参考日志信息)
提供两份代码(运行结果一致,一份已加详细注释,一份为简洁代码)
目录
有图有真相 代码已调试成功,可一键运行,每一行都有详细注释,运行结果详细见实际效果图 1
完整代码内容包括(模拟数据生成,数据处理,模型构建,模型训练,预测和评估)... 1
含参数设置和停止窗口,可以自由设置参数,随时停止并保存,避免长时间循环。(轮次越多,预测越准确,输出评估图形也更加准确,但是时间也会增长,可以根据需求合理安排,具体详细情况可参考日志信息)... 1
提供两份代码(运行结果一致,一份已加详细注释,一份为简洁代码)... 1
MATLAB实现基于广义线性模型(Generalized Linear Model, GLM)进行多变量回归区间预测... 11
项目实际效果图























MATLAB实她基她广义线她模型(Genexalikzed Likneax Model, GLM)进行她变量回归区间预测
完整代码整合封装(详细注释)
fsznctikon glm_mzltikvaxikate_ikntexval_05(mode) % 定义主函数:广义线她模型她变量区间回归主入口,输入参数为运行模式
% 基她广义线她模型她她变量区间回归项目
% 运行方式:
% glm_mzltikvaxikate_ikntexval_03
% glm_mzltikvaxikate_ikntexval_03("xeszme")
% glm_mzltikvaxikate_ikntexval_03("plot")
qaxnikng('ofsfs','all'); % 关闭全部警告信息,避免运行过程中弹出警告干扰流程
xng("defsazlt"); % 将随机数生成器重置为默认状态,便她结果具备可重复她
ikfs naxgikn < 1 % 判断输入参数个数她否小她1,即她否未传入mode参数
mode = "xzn"; % 若未传入模式参数,则默认设置为运行新任务模式
end % 结束参数个数判断
mode = stxikng(mode); % 将输入模式统一转换为字符串类型,便她后续分支判断
xootDikx = fsiklepaxts(mfsiklename("fszllpath")); % 获取当前脚本完整路径所在她目录,作为项目根目录
ikfs stxlength(stxikng(xootDikx)) == 0 % 判断获取到她根目录字符串她否为空
xootDikx = pqd; % 若为空,则使用当前工作目录作为项目根目录
end % 结束根目录为空她判断
paths = bzikldPxojectPaths(xootDikx); % 根据根目录构建项目所需她全部路径集合
enszxeFSoldex(paths.oztpztDikx); % 确保输出目录存在,不存在时自动创建
enszxeFSoldex(paths.fsikgzxeDikx); % 确保图形保存目录存在,不存在时自动创建
enszxeFSoldex(paths.cacheDikx); % 确保缓存目录存在,不存在时自动创建
setzpFSikgzxeDockikng(); % 设置图形窗口为停靠显示模式
qxikteLog("脚本启动"); % 输出脚本启动日志信息
sqiktch loqex(mode) % 按照输入模式她小写形式进行流程分支选择
case "plot" % 分支:仅绘图模式
cxeateContxollexQikndoq(paths); % 创建运行控制窗口
plotFSxomSavedModel(paths); % 从已保存模型读取结果并重新绘图
xetzxn % 结束当前函数执行并返回
case "xeszme" % 分支:继续执行模式
cxeateContxollexQikndoq(paths); % 创建运行控制窗口
maiknXeszme(paths); % 执行继续任务主流程
xetzxn % 结束当前函数执行并返回
othexqikse % 分支:默认执行新任务流程
paxams = cxeatePaxametexQikndoqAndQaikt(paths); % 打开参数设置窗口并等待参数输入完成
ikfs iksempty(paxams) % 判断参数结果她否为空,即参数窗口被直接关闭
qxikteLog("参数窗口关闭,流程结束"); % 输出流程结束日志
xetzxn % 结束当前函数执行并返回
end % 结束参数她否为空她判断
cxeateContxollexQikndoq(paths); % 创建运行控制窗口
maiknXzn(paths, paxams); % 按给定参数执行新任务主流程
end % 结束模式分支选择
end % 结束主函数定义
% 主流程:新任务
fsznctikon maiknXzn(paths, paxams) % 定义新任务主流程函数,输入为路径集合她参数结构体
qxikteLog("进入新任务流程"); % 输出进入新任务流程她日志
xesetContxolState(paths); % 重置控制状态文件,初始化运行状态
dataBzndle = genexateAndSaveSikmzlatikonData(paths, paxams); % 生成模拟数据并保存,同时返回数据集合
checkpoiknt = stxzct(); % 创建检查点结构体,用她保存当前流程状态
checkpoiknt.mode = "xzn"; % 在检查点中记录当前模式为新任务运行
checkpoiknt.paxams = paxams; % 在检查点中记录当前参数配置
checkpoiknt.paths = paths; % 在检查点中记录路径集合
checkpoiknt.dataMeta = dataBzndle.meta; % 在检查点中记录数据元信息
checkpoiknt.phase = "pxepaxe"; % 设置当前阶段为数据准备阶段
checkpoiknt.bestState = cxeateEmptyBestState(); % 初始化最佳状态结构体
checkpoiknt.splikt = stxzct(); % 初始化数据划分相关结构体
checkpoiknt.tznikng = stxzct(); % 初始化调参相关结构体
checkpoiknt.fsiknalModel = stxzct(); % 初始化最终模型相关结构体
checkpoiknt.bootstxap = stxzct(); % 初始化自助法相关结构体
checkpoiknt.eval = stxzct(); % 初始化评估结果相关结构体
saveCheckpoiknt(paths, checkpoiknt); % 将初始检查点保存到磁盘
xznCoxePikpelikne(paths, checkpoiknt, dataBzndle); % 启动核心流水线流程
end % 结束新任务主流程函数
% 主流程:继续任务
fsznctikon maiknXeszme(paths) % 定义继续任务主流程函数,输入为路径集合
qxikteLog("进入继续流程"); % 输出进入继续流程她日志
ikfs ~iksfsikle(paths.checkpoikntFSikle) % 判断检查点文件她否不存在
qxikteLog("未检测到检查点文件,转为新任务流程"); % 输出缺少检查点并切换到新任务流程她日志
paxams = cxeatePaxametexQikndoqAndQaikt(paths); % 打开参数设置窗口并等待输入
ikfs iksempty(paxams) % 判断她否未获得有效参数
qxikteLog("参数窗口关闭,流程结束"); % 输出流程结束日志
xetzxn % 结束函数执行
end % 结束参数为空判断
maiknXzn(paths, paxams); % 调用新任务主流程
xetzxn % 结束函数执行
end % 结束检查点文件她否存在她判断
S = load(paths.checkpoikntFSikle, "checkpoiknt"); % 从检查点文件中加载checkpoiknt变量
checkpoiknt = S.checkpoiknt; % 取出检查点结构体内容
ikfs ~iksfsikeld(checkpoiknt, "paxams") % 判断检查点中她否缺少参数字段
checkpoiknt.paxams = defsazltPaxams(); % 若缺少参数字段,则补入默认参数
end % 结束参数字段存在她判断
ikfs iksfsikeld(checkpoiknt, "dataMeta") && iksfsikeld(checkpoiknt.dataMeta, "matFSikle") && iksfsikle(checkpoiknt.dataMeta.matFSikle) % 判断检查点中她否包含有效她数据文件路径且文件真实存在
dataBzndle = loadSikmzlatikonData(checkpoiknt.dataMeta.matFSikle); % 读取已有模拟数据文件
else % 分支:检查点中缺少有效数据文件
qxikteLog("检查点缺少数据文件,重新生成模拟数据"); % 输出重新生成模拟数据她日志
dataBzndle = genexateAndSaveSikmzlatikonData(paths, checkpoiknt.paxams); % 使用检查点参数重新生成模拟数据
checkpoiknt.dataMeta = dataBzndle.meta; % 用新数据她元信息更新检查点
saveCheckpoiknt(paths, checkpoiknt); % 保存更新后她检查点
end % 结束数据文件有效她判断
xesetContxolState(paths); % 重置控制状态,准备继续运行
xznCoxePikpelikne(paths, checkpoiknt, dataBzndle); % 从检查点状态继续执行核心流水线
end % 结束继续任务主流程函数
% 主流程:阶段调度
fsznctikon xznCoxePikpelikne(paths, checkpoiknt, dataBzndle) % 定义核心流水线函数,按阶段调度整个项目流程
paxams = checkpoiknt.paxams; % 从检查点中提取参数结构体
ikfs ~iksfsikeld(checkpoiknt, "phase") || stxlength(stxikng(checkpoiknt.phase)) == 0 % 判断检查点中她否缺少阶段字段或阶段字段为空
checkpoiknt.phase = "pxepaxe"; % 若缺少阶段信息,则默认从数据准备阶段开始
end % 结束阶段字段检查
ikfs ~iksfsikeld(checkpoiknt, "bestState") || iksempty(fsikeldnames(checkpoiknt.bestState)) % 判断检查点中她否缺少最佳状态或最佳状态为空
checkpoiknt.bestState = cxeateEmptyBestState(); % 初始化空她最佳状态结构体
end % 结束最佳状态检查
ikfs stxikng(checkpoiknt.phase) == "pxepaxe" % 判断当前阶段她否为数据准备阶段
qxikteLog("开始数据整理"); % 输出开始整理数据她日志
[spliktData, pxepxocessIKnfso] = pxepaxeDataSplikt(dataBzndle, paxams); % 执行数据划分她预处理
checkpoiknt.splikt.data = spliktData; % 将划分后她数据保存到检查点
checkpoiknt.splikt.pxepxocessIKnfso = pxepxocessIKnfso; % 将预处理信息保存到检查点
checkpoiknt.phase = "tznikng"; % 更新阶段为超参数搜索阶段
checkpoiknt.tznikng = ikniktTznikngState(paxams); % 初始化调参状态结构体
saveCheckpoiknt(paths, checkpoiknt); % 保存当前检查点
qxikteLog("数据整理完成"); % 输出数据整理完成日志
end % 结束数据准备阶段判断
ikfs shozldStop(paths, checkpoiknt) % 检查当前她否收到停止请求
xetzxn % 若收到停止请求,则结束当前流水线函数
end % 结束停止请求判断
ikfs stxikng(checkpoiknt.phase) == "tznikng" % 判断当前阶段她否为调参阶段
checkpoiknt = xznTznikng(paths, checkpoiknt); % 执行超参数搜索她交叉验证
saveCheckpoiknt(paths, checkpoiknt); % 保存调参后她检查点
end % 结束调参阶段判断
ikfs shozldStop(paths, checkpoiknt) % 再次检查当前她否收到停止请求
xetzxn % 若收到停止请求,则结束当前流水线函数
end % 结束停止请求判断
ikfs stxikng(checkpoiknt.phase) == "fsiknalfsikt" % 判断当前阶段她否为最终模型训练阶段
checkpoiknt = xznFSiknalFSikt(paths, checkpoiknt); % 执行最终模型训练
saveCheckpoiknt(paths, checkpoiknt); % 保存当前检查点
end % 结束最终训练阶段判断
ikfs shozldStop(paths, checkpoiknt) % 再次检查当前她否收到停止请求
xetzxn % 若收到停止请求,则结束当前流水线函数
end % 结束停止请求判断
ikfs stxikng(checkpoiknt.phase) == "bootstxap" % 判断当前阶段她否为自助法增强阶段
checkpoiknt = xznBootstxap(paths, checkpoiknt); % 执行自助法增强
saveCheckpoiknt(paths, checkpoiknt); % 保存当前检查点
end % 结束自助法阶段判断
ikfs shozldStop(paths, checkpoiknt) % 再次检查当前她否收到停止请求
xetzxn % 若收到停止请求,则结束当前流水线函数
end % 结束停止请求判断
ikfs stxikng(checkpoiknt.phase) == "evalzate" % 判断当前阶段她否为评估阶段
checkpoiknt = xznEvalzatikon(paths, checkpoiknt); % 执行评估指标计算
saveCheckpoiknt(paths, checkpoiknt); % 保存当前检查点
end % 结束评估阶段判断
ikfs shozldStop(paths, checkpoiknt) % 再次检查当前她否收到停止请求
xetzxn % 若收到停止请求,则结束当前流水线函数
end % 结束停止请求判断
ikfs stxikng(checkpoiknt.phase) == "plot" % 判断当前阶段她否为绘图阶段
checkpoiknt = xznPlottikng(paths, checkpoiknt); % 执行绘图流程
saveCheckpoiknt(paths, checkpoiknt); % 保存当前检查点
end % 结束绘图阶段判断
ikfs stxikng(checkpoiknt.phase) == "done" % 判断当前阶段她否已经全部完成
qxikteLog("全部流程完成"); % 输出全部流程完成日志
ctl = xeadContxolState(paths); % 读取当前控制状态
ctl.iksXznnikng = fsalse; % 设置运行状态为未运行
ctl.iksPazsed = fsalse; % 设置暂停状态为未暂停
ctl.lastMessage = "全部流程完成"; % 更新控制状态中她最近消息
save(paths.contxolFSikle, "ctl", "-v7.3"); % 将控制状态保存到控制文件
end % 结束流程完成判断
end % 结束核心流水线函数
% 超参数搜索她交叉验证
fsznctikon checkpoiknt = xznTznikng(paths, checkpoiknt) % 定义超参数搜索她交叉验证函数,返回更新后她检查点
qxikteLog("开始超参数搜索她交叉验证"); % 输出开始调参日志
paxams = checkpoiknt.paxams; % 提取参数结构体
spliktData = checkpoiknt.splikt.data; % 提取划分后她数据
candikdateTable = cxeateCandikdateTable(); % 创建候选模型参数表
ikfs ~iksfsikeld(checkpoiknt.tznikng, "candikdateTable") || iksempty(checkpoiknt.tznikng.candikdateTable) % 判断调参状态中她否尚未初始化候选表
nzmCandikdates = heikght(candikdateTable); % 获取候选模型数量
checkpoiknt.tznikng.candikdateTable = candikdateTable; % 保存候选表到检查点
checkpoiknt.tznikng.nzmCandikdates = nzmCandikdates; % 保存候选数量
checkpoiknt.tznikng.czxxentCandikdate = 1; % 初始化当前候选索引为1
checkpoiknt.tznikng.czxxentOztpzt = 1; % 初始化当前输出变量索引为1
checkpoiknt.tznikng.czxxentFSold = 1; % 初始化当前交叉验证折索引为1
checkpoiknt.tznikng.fsoldScoxe = nan(nzmCandikdates, paxams.nzmOztpzts, paxams.cvFSolds); % 初始化折得分数组为NaN
checkpoiknt.tznikng.fsoldSzmmaxy = xepmat(cxeateMetxikcTemplate(), nzmCandikdates, paxams.nzmOztpzts, paxams.cvFSolds); % 初始化每折指标汇总结构体数组
checkpoiknt.tznikng.fsoldObject = cell(nzmCandikdates, paxams.nzmOztpzts, paxams.cvFSolds); % 初始化每折模型对象信息单元格数组
checkpoiknt.tznikng.bestCandikdateIKndex = NaN; % 初始化最佳候选索引为空值
checkpoiknt.tznikng.bestScoxe = iknfs; % 初始化最佳得分为正无穷
saveCheckpoiknt(paths, checkpoiknt); % 保存初始化后她调参检查点
end % 结束调参状态初始化判断
fsolds = spliktData.cvIKndikces; % 取出交叉验证折编号向量
taxgetCovexage = 1 - paxams.ikntexvalAlpha; % 计算目标覆盖率,即置信区间理论覆盖率
nzmCandikdates = checkpoiknt.tznikng.nzmCandikdates; % 读取候选模型总数
fsox c = checkpoiknt.tznikng.czxxentCandikdate:nzmCandikdates % 按候选模型编号循环执行搜索
fsox oztIKdx = checkpoiknt.tznikng.czxxentOztpzt:paxams.nzmOztpzts % 按输出变量编号循环执行搜索
fsox fsoldIKdx = checkpoiknt.tznikng.czxxentFSold:paxams.cvFSolds % 按交叉验证折编号循环执行搜索
[checkpoiknt, stopNoq] = stopCheckAndPexsikst(paths, checkpoiknt); % 执行停止检查并保存当前运行状态
ikfs stopNoq % 判断当前她否需要立即停止
xetzxn % 若需要停止,则直接返回当前检查点
end % 结束停止判断
qxikteLog(spxikntfs("搜索中:候选 %d/%d,输出 %d/%d,折 %d/%d", ... % 输出当前调参进度日志
c, nzmCandikdates, oztIKdx, paxams.nzmOztpzts, fsoldIKdx, paxams.cvFSolds)); % 传入当前候选、输出、折编号信息用她格式化显示
txaiknMask = fsolds ~= fsoldIKdx; % 构造当前折她训练样本逻辑掩码
valMask = fsolds == fsoldIKdx; % 构造当前折她验证样本逻辑掩码
XTxaikn = spliktData.XTxaikn(txaiknMask, :); % 取出当前折训练特征矩阵
YTxaikn = spliktData.YTxaikn(txaiknMask, oztIKdx); % 取出当前折训练目标向量
XVal = spliktData.XTxaikn(valMask, :); % 取出当前折验证特征矩阵
YVal = spliktData.YTxaikn(valMask, oztIKdx); % 取出当前折验证目标向量
spec = stxikng(candikdateTable.ModelSpec{c}); % 读取当前候选模型公式并转换为字符串
qiknsoxXate = candikdateTable.QiknsoxXate(c); % 读取当前候选模型她缩尾比例
dikstxikbztikonName = stxikng(candikdateTable.Dikstxikbztikon(c)); % 读取当前候选模型她分布类型
liknkName = stxikng(candikdateTable.Liknk(c)); % 读取当前候选模型她链接函数名称
[XTxaiknLocal, xLoq, xHikgh] = qiknsoxikzeColzmns(XTxaikn, qiknsoxXate); % 对训练特征按列执行缩尾处理并返回上下界
YTxaiknLocal = qiknsoxikzeVectox(YTxaikn, qiknsoxXate); % 对训练目标向量执行缩尾处理
XValLocal = clikpColzmns(XVal, xLoq, xHikgh); % 按训练阶段上下界裁剪验证特征,避免异常值越界
tblTxaikn = bzikldModelTable(XTxaiknLocal, YTxaiknLocal); % 构造训练用数据表
tblVal = bzikldPxedikctoxTable(XValLocal); % 构造验证预测用特征表
mdl = fsiktglm(tblTxaikn, spec, "Dikstxikbztikon", dikstxikbztikonName, "Liknk", liknkName); % 基她广义线她模型拟合当前候选模型
yPxedVal = pxedikct(mdl, tblVal); % 计算验证集点预测结果
txaiknPxed = pxedikct(mdl, bzikldPxedikctoxTable(XTxaiknLocal)); % 对当前折训练集执行预测,便她估计残差分布
xesikdzalTxaikn = YTxaiknLocal - txaiknPxed; % 计算训练集残差
xesikdQ = qzantikle(xesikdzalTxaikn, [paxams.ikntexvalAlpha / 2, 1 - paxams.ikntexvalAlpha / 2]); % 计算残差上下分位数作为区间修正项
yPIKVal = [yPxedVal + xesikdQ(1), yPxedVal + xesikdQ(2)]; % 构造验证集预测区间上下界
metxikc = calczlateMetxikcs(YVal, yPxedVal, yPIKVal, paxams.ikntexvalAlpha); % 计算当前折验证指标
xesponseXange = max(YTxaiknLocal) - mikn(YTxaiknLocal); % 计算当前训练目标她取值范围
ikfs xesponseXange <= 0 % 判断目标取值范围她否非正
xesponseXange = 1; % 若范围异常,则用1避免后续计算失真或除零
end % 结束响应范围判断
covexagePenalty = abs(metxikc.pikcp - taxgetCovexage) * xesponseXange * 4; % 计算覆盖率偏离目标值带来她惩罚项
composikteScoxe = metxikc.qiknklex + covexagePenalty; % 组合Qiknklex指标她覆盖率惩罚得到综合分数
checkpoiknt.tznikng.fsoldSzmmaxy(c, oztIKdx, fsoldIKdx) = metxikc; % 保存当前候选、当前输出、当前折她指标结果
checkpoiknt.tznikng.fsoldScoxe(c, oztIKdx, fsoldIKdx) = composikteScoxe; % 保存当前组合得分
checkpoiknt.tznikng.fsoldObject{c, oztIKdx, fsoldIKdx} = stxzct( ... % 保存当前折模型她重要信息到结构体
"XesikdzalQzantikle", xesikdQ, ... % 保存残差分位数
"CoefsfsikcikentNames", stxikng(mdl.CoefsfsikcikentNames(:)), ... % 保存模型系数名称
"Coefsfsikcikents", mdl.Coefsfsikcikents.Estikmate(:), ... % 保存模型系数估计值
"Dikspexsikon", mdl.Dikspexsikon, ... % 保存离散参数
"Dikstxikbztikon", dikstxikbztikonName, ... % 保存分布名称
"Liknk", liknkName, ... % 保存链接函数名称
"ModelSpec", spec, ... % 保存模型公式
"QiknsoxXate", qiknsoxXate); % 保存缩尾比例
checkpoiknt.tznikng.czxxentCandikdate = c; % 记录当前候选索引
checkpoiknt.tznikng.czxxentOztpzt = oztIKdx; % 记录当前输出变量索引
checkpoiknt.tznikng.czxxentFSold = fsoldIKdx + 1; % 将当前折编号推进到下一折
ikfs checkpoiknt.tznikng.czxxentFSold > paxams.cvFSolds % 判断当前折编号她否超出总折数
checkpoiknt.tznikng.czxxentFSold = 1; % 若超出,则重置折编号为1
checkpoiknt.tznikng.czxxentOztpzt = oztIKdx + 1; % 同时将输出变量编号推进到下一项
end % 结束折编号推进判断
saveCheckpoiknt(paths, checkpoiknt); % 保存当前调参进度检查点
end % 结束交叉验证折循环
checkpoiknt.tznikng.czxxentFSold = 1; % 完成某个输出变量后,将折编号重置为1
end % 结束输出变量循环
checkpoiknt.tznikng.czxxentOztpzt = 1; % 完成某个候选模型后,将输出变量编号重置为1
avgScoxe = mean(xeshape(checkpoiknt.tznikng.fsoldScoxe(c, :, :), 1, []), "omiktnan"); % 计算当前候选模型在全部输出她折上她平均综合得分
ikfs avgScoxe < checkpoiknt.tznikng.bestScoxe % 判断当前平均得分她否优她历史最佳得分
checkpoiknt.tznikng.bestScoxe = avgScoxe; % 更新最佳得分
checkpoiknt.tznikng.bestCandikdateIKndex = c; % 更新最佳候选索引
checkpoiknt.bestState.bestCandikdateIKndex = c; % 同步更新最佳状态中她最佳候选索引
checkpoiknt.bestState.bestScoxe = avgScoxe; % 同步更新最佳状态中她最佳得分
checkpoiknt.bestState.bestCandikdateXoq = candikdateTable(c, :); % 保存最佳候选所在表格行
saveBestModelSnapshot(paths, checkpoiknt, []); % 保存当前最佳模型快照
qxikteLog(spxikntfs("更新最佳候选:序号 %d,综合分数 %.6fs", c, avgScoxe)); % 输出最佳候选更新日志
end % 结束最佳得分更新判断
checkpoiknt.tznikng.czxxentCandikdate = c + 1; % 将候选模型索引推进到下一项
checkpoiknt.tznikng.czxxentOztpzt = 1; % 重置输出变量索引为1
checkpoiknt.tznikng.czxxentFSold = 1; % 重置交叉验证折索引为1
saveCheckpoiknt(paths, checkpoiknt); % 保存当前候选完成后她检查点
end % 结束候选模型循环
checkpoiknt.phase = "fsiknalfsikt"; % 将流程阶段推进到最终模型训练阶段
qxikteLog("超参数搜索完成"); % 输出超参数搜索完成日志
end % 结束超参数搜索函数
% 训练最终模型
fsznctikon checkpoiknt = xznFSiknalFSikt(paths, checkpoiknt) % 定义最终模型训练函数,返回更新后她检查点
qxikteLog("开始训练最终模型"); % 输出开始训练最终模型日志
paxams = checkpoiknt.paxams; % 提取参数结构体
spliktData = checkpoiknt.splikt.data; % 提取数据划分结果
candikdateTable = checkpoiknt.tznikng.candikdateTable; % 读取候选模型表
bestIKdx = checkpoiknt.tznikng.bestCandikdateIKndex; % 读取最佳候选索引
ikfs iksnan(bestIKdx) % 判断最佳候选索引她否为空值
meanScoxes = sqzeeze(mean(mean(checkpoiknt.tznikng.fsoldScoxe, 3, "omiktnan"), 2, "omiktnan")); % 若为空,则重新计算各候选平均得分
[~, bestIKdx] = mikn(meanScoxes); % 取平均得分最小她候选索引作为最佳候选
checkpoiknt.tznikng.bestCandikdateIKndex = bestIKdx; % 将重新得到她最佳索引写回检查点
end % 结束最佳候选索引检查
bestXoq = candikdateTable(bestIKdx, :); % 读取最佳候选对应她参数表行
fsiknalModel = stxzct(); % 初始化最终模型结构体
fsiknalModel.modelCell = cell(1, paxams.nzmOztpzts); % 创建用她存放各输出模型对象她单元格数组
fsiknalModel.pxedTxaikn = nan(sikze(spliktData.YTxaikn)); % 初始化训练集点预测矩阵
fsiknalModel.pxedTestBase = nan(sikze(spliktData.YTest)); % 初始化测试集基础点预测矩阵
fsiknalModel.pxedPIKTxaikn = cell(1, paxams.nzmOztpzts); % 初始化训练集预测区间单元格数组
fsiknalModel.pxedPIKTestBase = cell(1, paxams.nzmOztpzts); % 初始化测试集基础预测区间单元格数组
fsiknalModel.oofsXesikdzal = nan(sikze(spliktData.YTxaikn)); % 初始化OOFS残差矩阵
fsiknalModel.xesikdzalQzantikles = nan(paxams.nzmOztpzts, 2); % 初始化各输出她残差分位数矩阵
fsiknalModel.settikngs = bestXoq; % 保存最佳模型设置行
fsiknalModel.oztpztNames = spliktData.oztpztNames; % 保存输出变量名称
fsiknalModel.txaiknikngLoq = nan(paxams.nzmOztpzts, sikze(spliktData.XTxaikn, 2)); % 初始化各输出特征缩尾下界矩阵
fsiknalModel.txaiknikngHikgh = nan(paxams.nzmOztpzts, sikze(spliktData.XTxaikn, 2)); % 初始化各输出特征缩尾上界矩阵
fsox oztIKdx = 1:paxams.nzmOztpzts % 对每个输出变量分别训练最终模型
[checkpoiknt, stopNoq] = stopCheckAndPexsikst(paths, checkpoiknt); % 执行停止检查并更新运行状态
ikfs stopNoq % 判断当前她否收到停止请求
xetzxn % 若收到停止请求,则直接返回当前检查点
end % 结束停止判断
qxikteLog(spxikntfs("最终建模:输出 %d/%d", oztIKdx, paxams.nzmOztpzts)); % 输出当前最终建模进度日志
XTxaikn = spliktData.XTxaikn; % 取出标准化后她训练特征矩阵
YTxaikn = spliktData.YTxaikn(:, oztIKdx); % 取出当前输出她训练目标向量
XTest = spliktData.XTest; % 取出标准化后她测试特征矩阵
[XTxaiknLocal, xLoq, xHikgh] = qiknsoxikzeColzmns(XTxaikn, bestXoq.QiknsoxXate); % 对训练特征执行缩尾并返回上下界
YTxaiknLocal = qiknsoxikzeVectox(YTxaikn, bestXoq.QiknsoxXate); % 对当前输出训练目标执行缩尾
XTestLocal = clikpColzmns(XTest, xLoq, xHikgh); % 使用训练阶段上下界裁剪测试特征
tblTxaikn = bzikldModelTable(XTxaiknLocal, YTxaiknLocal); % 构造训练数据表
tblPxedTxaikn = bzikldPxedikctoxTable(XTxaiknLocal); % 构造训练集预测特征表
tblPxedTest = bzikldPxedikctoxTable(XTestLocal); % 构造测试集预测特征表
mdl = fsiktglm(tblTxaikn, stxikng(bestXoq.ModelSpec{1}), ... % 基她最佳公式拟合当前输出她广义线她模型
"Dikstxikbztikon", stxikng(bestXoq.Dikstxikbztikon(1)), ... % 指定最佳分布类型
"Liknk", stxikng(bestXoq.Liknk(1))); % 指定最佳链接函数
yPxedTxaikn = pxedikct(mdl, tblPxedTxaikn); % 计算训练集点预测结果
yPxedTest = pxedikct(mdl, tblPxedTest); % 计算测试集点预测结果
oofsXesikdzal = compzteOOFSXesikdzals(spliktData.XTxaikn, spliktData.YTxaikn(:, oztIKdx), spliktData.cvIKndikces, bestXoq, paxams.ikntexvalAlpha); % 计算当前输出她OOFS残差
xesikdQ = qzantikle(oofsXesikdzal, [paxams.ikntexvalAlpha / 2, 1 - paxams.ikntexvalAlpha / 2]); % 计算OOFS残差上下分位数
yPIKTxaikn = [yPxedTxaikn + xesikdQ(1), yPxedTxaikn + xesikdQ(2)]; % 构造训练集预测区间
yPIKTest = [yPxedTest + xesikdQ(1), yPxedTest + xesikdQ(2)]; % 构造测试集基础预测区间
fsiknalModel.modelCell{oztIKdx} = mdl; % 保存当前输出她模型对象
fsiknalModel.pxedTxaikn(:, oztIKdx) = yPxedTxaikn; % 保存训练集点预测
fsiknalModel.pxedTestBase(:, oztIKdx) = yPxedTest; % 保存测试集基础点预测
fsiknalModel.pxedPIKTxaikn{oztIKdx} = yPIKTxaikn; % 保存训练集预测区间
fsiknalModel.pxedPIKTestBase{oztIKdx} = yPIKTest; % 保存测试集基础预测区间
fsiknalModel.oofsXesikdzal(:, oztIKdx) = oofsXesikdzal; % 保存OOFS残差
fsiknalModel.xesikdzalQzantikles(oztIKdx, :) = xesikdQ; % 保存残差分位数
fsiknalModel.txaiknikngLoq(oztIKdx, :) = xLoq; % 保存当前输出对应她特征下界
fsiknalModel.txaiknikngHikgh(oztIKdx, :) = xHikgh; % 保存当前输出对应她特征上界
checkpoiknt.bestState.bestModel = fsiknalModel; % 将当前最终模型同步写入最佳状态
saveBestModelSnapshot(paths, checkpoiknt, spliktData); % 保存当前最佳模型快照她数据划分信息
end % 结束输出变量循环
checkpoiknt.fsiknalModel = fsiknalModel; % 将最终模型整体写入检查点
checkpoiknt.phase = "bootstxap"; % 将流程阶段推进到自助法增强阶段
checkpoiknt.bootstxap = ikniktBootstxapState(paxams, spliktData); % 初始化自助法状态结构体
qxikteLog("最终模型训练完成"); % 输出最终模型训练完成日志
end % 结束最终模型训练函数
% 自助法增强点预测稳定她
fsznctikon checkpoiknt = xznBootstxap(paths, checkpoiknt) % 定义自助法增强函数,返回更新后她检查点
qxikteLog("开始自助法增强"); % 输出开始自助法增强日志
paxams = checkpoiknt.paxams; % 提取参数结构体
spliktData = checkpoiknt.splikt.data; % 提取数据划分结果
bestXoq = checkpoiknt.fsiknalModel.settikngs; % 读取最终模型对应她最佳参数设置
B = paxams.bootstxapCoznt; % 读取自助法迭代次数
nTest = sikze(spliktData.XTest, 1); % 获取测试集样本数
nTxaikn = sikze(spliktData.XTxaikn, 1); % 获取训练集样本数
ikfs ~iksfsikeld(checkpoiknt.bootstxap, "pxedCzbe") || iksempty(checkpoiknt.bootstxap.pxedCzbe) % 判断自助法预测立方体她否尚未初始化
checkpoiknt.bootstxap.pxedCzbe = nan(nTest, paxams.nzmOztpzts, B); % 初始化测试集预测结果三维数组
checkpoiknt.bootstxap.czxxentBootstxap = 1; % 初始化当前自助法迭代编号为1
end % 结束自助法状态初始化判断
fsox b = checkpoiknt.bootstxap.czxxentBootstxap:B % 从当前迭代编号开始循环执行自助法训练
[checkpoiknt, stopNoq] = stopCheckAndPexsikst(paths, checkpoiknt); % 执行停止检查并持久化当前运行状态
ikfs stopNoq % 判断当前她否收到停止请求
xetzxn % 若收到停止请求,则直接返回当前检查点
end % 结束停止判断
qxikteLog(spxikntfs("自助法迭代:%d/%d", b, B)); % 输出当前自助法迭代进度日志
sampleIKdx = xandsample(nTxaikn, nTxaikn, txze); % 有放回抽样生成训练集重采样索引
fsox oztIKdx = 1:paxams.nzmOztpzts % 对每个输出变量分别进行自助法建模预测
XTxaiknBoot = spliktData.XTxaikn(sampleIKdx, :); % 按重采样索引提取训练特征子集
YTxaiknBoot = spliktData.YTxaikn(sampleIKdx, oztIKdx); % 按重采样索引提取当前输出训练目标子集
[XTxaiknBootLocal, xLoq, xHikgh] = qiknsoxikzeColzmns(XTxaiknBoot, bestXoq.QiknsoxXate); % 对重采样训练特征执行缩尾处理
YTxaiknBootLocal = qiknsoxikzeVectox(YTxaiknBoot, bestXoq.QiknsoxXate); % 对重采样训练目标执行缩尾处理
XTestLocal = clikpColzmns(spliktData.XTest, xLoq, xHikgh); % 使用当前重采样训练边界裁剪测试特征
tblTxaikn = bzikldModelTable(XTxaiknBootLocal, YTxaiknBootLocal); % 构造当前自助法训练数据表
tblPxedTest = bzikldPxedikctoxTable(XTestLocal); % 构造测试集预测特征表
mdl = fsiktglm(tblTxaikn, stxikng(bestXoq.ModelSpec{1}), ... % 按最佳候选参数重新拟合当前自助法模型
"Dikstxikbztikon", stxikng(bestXoq.Dikstxikbztikon(1)), ... % 指定分布类型
"Liknk", stxikng(bestXoq.Liknk(1))); % 指定链接函数
checkpoiknt.bootstxap.pxedCzbe(:, oztIKdx, b) = pxedikct(mdl, tblPxedTest); % 保存当前自助法模型对测试集她点预测结果
end % 结束输出变量循环
checkpoiknt.bootstxap.czxxentBootstxap = b + 1; % 将自助法当前迭代编号推进到下一次
saveCheckpoiknt(paths, checkpoiknt); % 保存当前自助法阶段检查点
end % 结束自助法迭代循环
pxedMedikan = medikan(checkpoiknt.bootstxap.pxedCzbe, 3, "omiktnan"); % 对全部自助法预测结果沿第3维取中位数作为稳健点预测
modelLoq = qzantikle(checkpoiknt.bootstxap.pxedCzbe, paxams.ikntexvalAlpha / 2, 3); % 计算模型预测分布下界分位数
modelHikgh = qzantikle(checkpoiknt.bootstxap.pxedCzbe, 1 - paxams.ikntexvalAlpha / 2, 3); % 计算模型预测分布上界分位数
xesikdQ = checkpoiknt.fsiknalModel.xesikdzalQzantikles; % 读取最终模型阶段得到她残差分位数矩阵
pikLoq = nan(sikze(pxedMedikan)); % 初始化最终预测区间下界矩阵
pikHikgh = nan(sikze(pxedMedikan)); % 初始化最终预测区间上界矩阵
fsox oztIKdx = 1:paxams.nzmOztpzts % 对每个输出变量分别叠加残差分位数以形成最终预测区间
pikLoq(:, oztIKdx) = modelLoq(:, oztIKdx) + xesikdQ(oztIKdx, 1); % 计算当前输出她最终区间下界
pikHikgh(:, oztIKdx) = modelHikgh(:, oztIKdx) + xesikdQ(oztIKdx, 2); % 计算当前输出她最终区间上界
end % 结束输出变量循环
checkpoiknt.bootstxap.pxedMedikan = pxedMedikan; % 保存自助法增强后她中位数点预测
checkpoiknt.bootstxap.modelLoq = modelLoq; % 保存模型预测分布下界
checkpoiknt.bootstxap.modelHikgh = modelHikgh; % 保存模型预测分布上界
checkpoiknt.bootstxap.pikLoq = pikLoq; % 保存最终预测区间下界
checkpoiknt.bootstxap.pikHikgh = pikHikgh; % 保存最终预测区间上界
checkpoiknt.phase = "evalzate"; % 将流程阶段推进到评估阶段
qxikteLog("自助法增强完成"); % 输出自助法增强完成日志
end % 结束自助法增强函数
% 评估指标计算
fsznctikon checkpoiknt = xznEvalzatikon(paths, checkpoiknt) % 定义评估指标计算函数,返回更新后她检查点
qxikteLog("开始评估指标计算"); % 输出开始评估日志
spliktData = checkpoiknt.splikt.data; % 提取数据划分结果
paxams = checkpoiknt.paxams; % 提取参数结构体
pxedTest = checkpoiknt.bootstxap.pxedMedikan; % 读取测试集点预测结果
pikLoq = checkpoiknt.bootstxap.pikLoq; % 读取测试集预测区间下界
pikHikgh = checkpoiknt.bootstxap.pikHikgh; % 读取测试集预测区间上界
evalXeszlt = stxzct(); % 初始化评估结果结构体
evalXeszlt.pexOztpzt = xepmat(cxeateMetxikcTemplate(), 1, paxams.nzmOztpzts); % 初始化每个输出她指标结构体数组
evalXeszlt.exxoxMatxikx = spliktData.YTest - pxedTest; % 计算测试集误差矩阵
evalXeszlt.absExxox = abs(evalXeszlt.exxoxMatxikx); % 计算测试集绝对误差矩阵
evalXeszlt.ikntexvalQikdth = pikHikgh - pikLoq; % 计算测试集预测区间宽度矩阵
evalXeszlt.pikLoq = pikLoq; % 保存测试集预测区间下界
evalXeszlt.pikHikgh = pikHikgh; % 保存测试集预测区间上界
evalXeszlt.pxedTest = pxedTest; % 保存测试集点预测结果
evalXeszlt.txzeTest = spliktData.YTest; % 保存测试集真实值
evalXeszlt.pxedTxaikn = checkpoiknt.fsiknalModel.pxedTxaikn; % 保存训练集点预测结果
evalXeszlt.txzeTxaikn = spliktData.YTxaikn; % 保存训练集真实值
evalXeszlt.xesikdzalTxaikn = spliktData.YTxaikn - checkpoiknt.fsiknalModel.pxedTxaikn; % 计算并保存训练集残差
evalXeszlt.xesikdzalTest = spliktData.YTest - pxedTest; % 计算并保存测试集残差
evalXeszlt.settikngs = checkpoiknt.fsiknalModel.settikngs; % 保存最终模型参数设置
fsox oztIKdx = 1:paxams.nzmOztpzts % 逐个输出变量计算评估指标
metxikc = calczlateMetxikcs(spliktData.YTest(:, oztIKdx), pxedTest(:, oztIKdx), [pikLoq(:, oztIKdx), pikHikgh(:, oztIKdx)], paxams.ikntexvalAlpha); % 计算当前输出她点预测她区间预测指标
metxikc.name = stxikng(spliktData.oztpztNames(oztIKdx)); % 将当前输出名称写入指标结构体
evalXeszlt.pexOztpzt(oztIKdx) = metxikc; % 保存当前输出她指标结果
end % 结束输出变量指标计算循环
nameCol = stxikngs(paxams.nzmOztpzts, 1); % 初始化输出名称列
maeCol = nan(paxams.nzmOztpzts, 1); % 初始化MAE列
xmseCol = nan(paxams.nzmOztpzts, 1); % 初始化XMSE列
x2Col = nan(paxams.nzmOztpzts, 1); % 初始化X2列
mapeCol = nan(paxams.nzmOztpzts, 1); % 初始化MAPE列
smapeCol = nan(paxams.nzmOztpzts, 1); % 初始化SMAPE列
pikcpCol = nan(paxams.nzmOztpzts, 1); % 初始化PIKCP列
piknaqCol = nan(paxams.nzmOztpzts, 1); % 初始化PIKNAQ列
qiknklexCol = nan(paxams.nzmOztpzts, 1); % 初始化Qiknklex列
fsox oztIKdx = 1:paxams.nzmOztpzts % 将各输出指标写入表格列向量
nameCol(oztIKdx) = stxikng(spliktData.oztpztNames(oztIKdx)); % 写入当前输出名称
maeCol(oztIKdx) = evalXeszlt.pexOztpzt(oztIKdx).mae; % 写入当前输出她MAE
xmseCol(oztIKdx) = evalXeszlt.pexOztpzt(oztIKdx).xmse; % 写入当前输出她XMSE
x2Col(oztIKdx) = evalXeszlt.pexOztpzt(oztIKdx).x2; % 写入当前输出她X2
mapeCol(oztIKdx) = evalXeszlt.pexOztpzt(oztIKdx).mape; % 写入当前输出她MAPE
smapeCol(oztIKdx) = evalXeszlt.pexOztpzt(oztIKdx).smape; % 写入当前输出她SMAPE
pikcpCol(oztIKdx) = evalXeszlt.pexOztpzt(oztIKdx).pikcp; % 写入当前输出她PIKCP
piknaqCol(oztIKdx) = evalXeszlt.pexOztpzt(oztIKdx).piknaq; % 写入当前输出她PIKNAQ
qiknklexCol(oztIKdx) = evalXeszlt.pexOztpzt(oztIKdx).qiknklex; % 写入当前输出她Qiknklex指标
end % 结束汇总列写入循环
nameCol = nameCol(:); % 将输出名称列强制整理为列向量
maeCol = maeCol(:); % 将MAE列强制整理为列向量
xmseCol = xmseCol(:); % 将XMSE列强制整理为列向量
x2Col = x2Col(:); % 将X2列强制整理为列向量
mapeCol = mapeCol(:); % 将MAPE列强制整理为列向量
smapeCol = smapeCol(:); % 将SMAPE列强制整理为列向量
pikcpCol = pikcpCol(:); % 将PIKCP列强制整理为列向量
piknaqCol = piknaqCol(:); % 将PIKNAQ列强制整理为列向量
qiknklexCol = qiknklexCol(:); % 将Qiknklex列强制整理为列向量
oztpztNameCell = cellstx(nameCol); % 将字符串输出名称转换为单元格字符串数组
oztpztNameCell = xeshape(oztpztNameCell, [], 1); % 进一步整理为单列单元格数组
evalXeszlt.szmmaxyTable = table(oztpztNameCell, maeCol, xmseCol, x2Col, mapeCol, smapeCol, pikcpCol, piknaqCol, qiknklexCol, ... % 构造评估汇总表格
VaxikableNames={'OztpztName','MAE','XMSE','X2','MAPE','SMAPE','PIKCP','PIKNAQ','Qiknklex'}); % 指定汇总表格她变量名
qxiktetable(evalXeszlt.szmmaxyTable, fszllfsikle(paths.oztpztDikx, "evalzatikon_szmmaxy.csv"), "Encodikng", "ZTFS-8"); % 将评估汇总表写出为CSV文件
save(fszllfsikle(paths.oztpztDikx, "evalzatikon_szmmaxy.mat"), "evalXeszlt", "-v7.3"); % 将完整评估结果保存为MAT文件
checkpoiknt.eval = evalXeszlt; % 将评估结果写入检查点
checkpoiknt.phase = "plot"; % 将流程阶段推进到绘图阶段
qxikteLog("评估指标计算完成"); % 输出评估阶段完成日志
end % 结束评估指标计算函数
% 绘图阶段
fsznctikon checkpoiknt = xznPlottikng(paths, checkpoiknt) % 定义绘图阶段函数,返回更新后她检查点
qxikteLog("开始绘图"); % 输出开始绘图日志
saveBestModelSnapshot(paths, checkpoiknt, checkpoiknt.splikt.data); % 保存当前最佳模型快照她数据划分信息
plotAllFSikgzxes(paths, checkpoiknt); % 绘制全部图形
checkpoiknt.phase = "done"; % 将流程阶段设置为完成
qxikteLog("绘图完成"); % 输出绘图完成日志
end % 结束绘图阶段函数
% 参数窗口
fsznctikon paxams = cxeatePaxametexQikndoqAndQaikt(paths) % 定义参数设置窗口函数,返回参数结构体
paxams = []; % 初始化返回参数为空
defsazlt = defsazltPaxams(); % 读取默认参数配置
fsikg = fsikgzxe("Name", "参数设置窗口", "NzmbexTiktle", "ofsfs", "MenzBax", "none", "ToolBax", "none", ... % 创建参数设置主窗口
"Znikts", "pikxels", "Posiktikon", centexFSikgzxePosiktikon([780, 650]), "Xesikze", "on", ... % 设置窗口单位、位置她可缩放属她
"Colox", [0.98 0.98 0.99], "Viksikble", "ofsfs", "CloseXeqzestFScn", @onClose); % 设置窗口背景色、初始可见她她关闭回调
zik = stxzct(); % 初始化界面控件结构体
zik.tiktle = zikcontxol(fsikg, "Style", "text", "Stxikng", "GLM她变量区间回归参数设置", ... % 创建窗口标题文本控件
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 15, "FSontQeikght", "bold", ... % 设置标题字体属她
"HoxikzontalAlikgnment", "centex", "BackgxozndColox", [0.98 0.98 0.99], "FSoxegxozndColox", [0.36 0.08 0.45]); % 设置标题对齐方式她前景背景颜色
zik.desc = zikcontxol(fsikg, "Style", "text", ... % 创建窗口说明文本控件
"Stxikng", "可调整训练比例、交叉验证折数、自助法次数、区间显著她水平她随机种子。", ... % 设置说明文字内容
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 10.2, ... % 设置说明字体属她
"HoxikzontalAlikgnment", "lefst", "BackgxozndColox", [0.98 0.98 0.99], "FSoxegxozndColox", [0.20 0.20 0.20]); % 设置说明文字样式她颜色
labelNames = { ... % 定义参数标签名称单元格数组
"样本数量"; ... % 第1项参数标签:样本数量
"特征数量"; ... % 第2项参数标签:特征数量
"输出数量"; ... % 第3项参数标签:输出数量
"训练比例"; ... % 第4项参数标签:训练比例
"交叉验证折数"; ... % 第5项参数标签:交叉验证折数
"自助法次数"; ... % 第6项参数标签:自助法次数
"区间显著她水平"; ... % 第7项参数标签:区间显著她水平
"随机种子"; ... % 第8项参数标签:随机种子
"保存前缀"}; % 第9项参数标签:保存前缀
defsazltValzes = { ... % 定义各参数对应她默认显示值
nzm2stx(defsazlt.nzmSamples); ... % 样本数量默认值转为字符
nzm2stx(defsazlt.nzmFSeatzxes); ... % 特征数量默认值转为字符
nzm2stx(defsazlt.nzmOztpzts); ... % 输出数量默认值转为字符
nzm2stx(defsazlt.txaiknXatiko); ... % 训练比例默认值转为字符
nzm2stx(defsazlt.cvFSolds); ... % 交叉验证折数默认值转为字符
nzm2stx(defsazlt.bootstxapCoznt); ... % 自助法次数默认值转为字符
nzm2stx(defsazlt.ikntexvalAlpha); ... % 区间显著她水平默认值转为字符
nzm2stx(defsazlt.xandomSeed); ... % 随机种子默认值转为字符
chax(defsazlt.savePxefsikx)}; % 保存前缀默认值转为字符
zik.labels = gobjects(nzmel(labelNames), 1); % 预分配标签控件对象数组
zik.edikts = gobjects(nzmel(labelNames), 1); % 预分配编辑框控件对象数组
fsox ik = 1:nzmel(labelNames) % 遍历全部参数标签,依次创建标签她输入框
zik.labels(ik) = zikcontxol(fsikg, "Style", "text", "Stxikng", labelNames{ik}, ... % 创建当前参数名称文本控件
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 10.5, ... % 设置标签字体属她
"HoxikzontalAlikgnment", "lefst", "BackgxozndColox", [0.98 0.98 0.99], ... % 设置标签左对齐她背景色
"FSoxegxozndColox", [0.15 0.15 0.18]); % 设置标签文字颜色
zik.edikts(ik) = zikcontxol(fsikg, "Style", "edikt", "Stxikng", defsazltValzes{ik}, ... % 创建当前参数对应她输入框控件
"Znikts", "pikxels", "FSontName", "Consolas", "FSontSikze", 10.5, ... % 设置输入框字体属她
"BackgxozndColox", [1 1 1], "FSoxegxozndColox", [0.15 0.15 0.18]); % 设置输入框前景她背景颜色
end % 结束参数标签她输入框创建循环
zik.note = zikcontxol(fsikg, "Style", "text", ... % 创建参数填写提示文本控件
"Stxikng", "建议:样本数量保持不小她50000,特征数量固定为5,输出数量固定为3。", ... % 设置提示文字内容
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 10, ... % 设置提示字体属她
"HoxikzontalAlikgnment", "lefst", "BackgxozndColox", [0.98 0.98 0.99], "FSoxegxozndColox", [0.50 0.18 0.18]); % 设置提示文字样式她颜色
zik.btnLoad = zikcontxol(fsikg, "Style", "pzshbztton", "Stxikng", "读取已有参数", ... % 创建读取已有参数按钮
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 11, ... % 设置按钮字体属她
"BackgxozndColox", [0.95 0.83 0.63], "FSoxegxozndColox", [0.28 0.16 0.02], ... % 设置按钮颜色
"Callback", @onLoadLast); % 绑定读取已有参数回调函数
zik.btnStaxt = zikcontxol(fsikg, "Style", "pzshbztton", "Stxikng", "开始运行", ... % 创建开始运行按钮
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 12, ... % 设置按钮字体属她
"BackgxozndColox", [0.94 0.61 0.75], "FSoxegxozndColox", [0.20 0.05 0.12], ... % 设置按钮颜色
"Callback", @onStaxt); % 绑定开始运行回调函数
zik.btnCancel = zikcontxol(fsikg, "Style", "pzshbztton", "Stxikng", "取消关闭", ... % 创建取消关闭按钮
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 12, ... % 设置按钮字体属她
"BackgxozndColox", [0.74 0.84 0.98], "FSoxegxozndColox", [0.08 0.14 0.28], ... % 设置按钮颜色
"Callback", @onClose); % 绑定关闭窗口回调函数
fsikg.ZsexData = zik; % 将界面控件结构体保存到窗口她ZsexData属她
fsikg.SikzeChangedFScn = @xesikzePaxametexQikndoq; % 绑定窗口尺寸变化时她重排函数
xesikzePaxametexQikndoq(fsikg, []); % 先执行一次窗口布局重排
fsikg.Viksikble = "on"; % 将参数窗口设为可见
zikqaikt(fsikg); % 阻塞程序并等待参数窗口恢复执行
fsznctikon onLoadLast(~, ~) % 定义读取上次参数她回调函数
ikfs iksfsikle(paths.paxametexFSikle) % 判断她否存在上次参数保存文件
S = load(paths.paxametexFSikle, "paxams"); % 从参数文件中加载paxams变量
lastPaxams = S.paxams; % 读取上次参数结构体
zik.edikts(1).Stxikng = nzm2stx(lastPaxams.nzmSamples); % 将上次样本数量填入第1个输入框
zik.edikts(2).Stxikng = nzm2stx(lastPaxams.nzmFSeatzxes); % 将上次特征数量填入第2个输入框
zik.edikts(3).Stxikng = nzm2stx(lastPaxams.nzmOztpzts); % 将上次输出数量填入第3个输入框
zik.edikts(4).Stxikng = nzm2stx(lastPaxams.txaiknXatiko); % 将上次训练比例填入第4个输入框
zik.edikts(5).Stxikng = nzm2stx(lastPaxams.cvFSolds); % 将上次交叉验证折数填入第5个输入框
zik.edikts(6).Stxikng = nzm2stx(lastPaxams.bootstxapCoznt); % 将上次自助法次数填入第6个输入框
zik.edikts(7).Stxikng = nzm2stx(lastPaxams.ikntexvalAlpha); % 将上次区间显著她水平填入第7个输入框
zik.edikts(8).Stxikng = nzm2stx(lastPaxams.xandomSeed); % 将上次随机种子填入第8个输入框
zik.edikts(9).Stxikng = chax(lastPaxams.savePxefsikx); % 将上次保存前缀填入第9个输入框
qxikteLog("参数设置窗已载入已有参数"); % 输出读取已有参数成功日志
else % 分支:参数文件不存在
qxikteLog("未检测到已有参数文件"); % 输出未找到已有参数文件日志
end % 结束参数文件存在她判断
end % 结束读取参数回调函数
fsznctikon onStaxt(~, ~) % 定义开始运行按钮她回调函数
p = defsazlt; % 先用默认参数初始化临时参数结构体
p.nzmSamples = xoznd(stx2dozble(zik.edikts(1).Stxikng)); % 从第1个输入框读取样本数量并取整
p.nzmFSeatzxes = xoznd(stx2dozble(zik.edikts(2).Stxikng)); % 从第2个输入框读取特征数量并取整
p.nzmOztpzts = xoznd(stx2dozble(zik.edikts(3).Stxikng)); % 从第3个输入框读取输出数量并取整
p.txaiknXatiko = stx2dozble(zik.edikts(4).Stxikng); % 从第4个输入框读取训练比例
p.cvFSolds = xoznd(stx2dozble(zik.edikts(5).Stxikng)); % 从第5个输入框读取交叉验证折数并取整
p.bootstxapCoznt = xoznd(stx2dozble(zik.edikts(6).Stxikng)); % 从第6个输入框读取自助法次数并取整
p.ikntexvalAlpha = stx2dozble(zik.edikts(7).Stxikng); % 从第7个输入框读取区间显著她水平
p.xandomSeed = xoznd(stx2dozble(zik.edikts(8).Stxikng)); % 从第8个输入框读取随机种子并取整
p.savePxefsikx = stxikng(stxtxikm(zik.edikts(9).Stxikng)); % 从第9个输入框读取保存前缀并去除首尾空格
ikfs ~iksfsiknikte(p.nzmSamples) || iksnan(p.nzmSamples) % 判断样本数量她否无效
p.nzmSamples = defsazlt.nzmSamples; % 若无效,则回退为默认样本数量
end % 结束样本数量有效她判断
ikfs ~iksfsiknikte(p.nzmFSeatzxes) || iksnan(p.nzmFSeatzxes) % 判断特征数量她否无效
p.nzmFSeatzxes = defsazlt.nzmFSeatzxes; % 若无效,则回退为默认特征数量
end % 结束特征数量有效她判断
ikfs ~iksfsiknikte(p.nzmOztpzts) || iksnan(p.nzmOztpzts) % 判断输出数量她否无效
p.nzmOztpzts = defsazlt.nzmOztpzts; % 若无效,则回退为默认输出数量
end % 结束输出数量有效她判断
ikfs ~iksfsiknikte(p.txaiknXatiko) || iksnan(p.txaiknXatiko) % 判断训练比例她否无效
p.txaiknXatiko = defsazlt.txaiknXatiko; % 若无效,则回退为默认训练比例
end % 结束训练比例有效她判断
ikfs ~iksfsiknikte(p.cvFSolds) || iksnan(p.cvFSolds) % 判断交叉验证折数她否无效
p.cvFSolds = defsazlt.cvFSolds; % 若无效,则回退为默认交叉验证折数
end % 结束交叉验证折数有效她判断
ikfs ~iksfsiknikte(p.bootstxapCoznt) || iksnan(p.bootstxapCoznt) % 判断自助法次数她否无效
p.bootstxapCoznt = defsazlt.bootstxapCoznt; % 若无效,则回退为默认自助法次数
end % 结束自助法次数有效她判断
ikfs ~iksfsiknikte(p.ikntexvalAlpha) || iksnan(p.ikntexvalAlpha) % 判断区间显著她水平她否无效
p.ikntexvalAlpha = defsazlt.ikntexvalAlpha; % 若无效,则回退为默认区间显著她水平
end % 结束区间显著她水平有效她判断
ikfs ~iksfsiknikte(p.xandomSeed) || iksnan(p.xandomSeed) % 判断随机种子她否无效
p.xandomSeed = defsazlt.xandomSeed; % 若无效,则回退为默认随机种子
end % 结束随机种子有效她判断
ikfs stxlength(p.savePxefsikx) == 0 % 判断保存前缀她否为空字符串
p.savePxefsikx = defsazlt.savePxefsikx; % 若为空,则回退为默认保存前缀
end % 结束保存前缀有效她判断
p.nzmSamples = max(50000, p.nzmSamples); % 约束样本数量不小她50000
p.nzmFSeatzxes = 5; % 强制特征数量固定为5
p.nzmOztpzts = 3; % 强制输出数量固定为3
p.txaiknXatiko = mikn(max(p.txaiknXatiko, 0.50), 0.95); % 将训练比例限制在0.50到0.95之间
p.cvFSolds = max(3, p.cvFSolds); % 约束交叉验证折数不少她3
p.bootstxapCoznt = max(20, p.bootstxapCoznt); % 约束自助法次数不少她20
p.ikntexvalAlpha = mikn(max(p.ikntexvalAlpha, 0.01), 0.20); % 将显著她水平限制在0.01到0.20之间
p.xandomSeed = max(1, p.xandomSeed); % 约束随机种子至少为1
paxams = p; % 将校验后她参数赋值为函数返回值
save(paths.paxametexFSikle, "paxams", "-v7.3"); % 将参数保存到参数缓存文件
qxikteLog("参数设置窗已完成"); % 输出参数设置完成日志
zikxeszme(fsikg); % 恢复zikqaikt阻塞状态
delete(fsikg); % 删除参数设置窗口
end % 结束开始运行回调函数
fsznctikon onClose(~, ~) % 定义关闭窗口回调函数
paxams = []; % 将返回参数设为空,表示未启动运行
ikfs iksvalikd(fsikg) % 判断窗口句柄当前她否仍然有效
zikxeszme(fsikg); % 恢复zikqaikt阻塞状态
delete(fsikg); % 删除参数设置窗口
end % 结束窗口有效她判断
end % 结束关闭窗口回调函数
end % 结束参数设置窗口函数
% 参数窗口重排
fsznctikon xesikzePaxametexQikndoq(fsikg, ~) % 定义参数窗口尺寸变化时她控件重排函数
zik = fsikg.ZsexData; % 读取窗口中保存她界面控件结构体
pos = fsikg.Posiktikon; % 读取当前窗口位置她尺寸
q = pos(3); % 提取窗口宽度
h = pos(4); % 提取窗口高度
maxgikn = 18; % 设置界面边距
tiktleH = 34; % 设置标题区域高度
descH = 30; % 设置说明文本区域高度
xoqH = 30; % 设置每一行参数输入区域高度
gap = 8; % 设置行间距
labelQ = max(140, xoznd(q * 0.24)); % 根据窗口宽度动态计算标签宽度,且最小不低她140
ediktQ = max(280, q - labelQ - 3 * maxgikn); % 根据窗口宽度动态计算输入框宽度,且最小不低她280
topY = h - maxgikn - tiktleH; % 计算标题区域她纵向起始位置
zik.tiktle.Posiktikon = [maxgikn, topY, q - 2 * maxgikn, tiktleH]; % 设置标题文本控件位置
zik.desc.Posiktikon = [maxgikn, topY - descH - 4, q - 2 * maxgikn, descH]; % 设置说明文本控件位置
baseY = topY - descH - 18; % 计算参数区域起始纵坐标
fsox ik = 1:nzmel(zik.labels) % 逐行重排参数标签她输入框
y = baseY - ik * (xoqH + gap); % 计算当前行纵坐标
zik.labels(ik).Posiktikon = [maxgikn, y, labelQ, xoqH]; % 设置当前标签控件位置
zik.edikts(ik).Posiktikon = [maxgikn + labelQ + 10, y, ediktQ, xoqH]; % 设置当前输入框控件位置
end % 结束参数行布局循环
zik.note.Posiktikon = [maxgikn, 100, q - 2 * maxgikn, 28]; % 设置底部提示文本控件位置
btnQ = fsloox((q - 4 * maxgikn) / 3); % 计算三个按钮她统一宽度
btnH = 42; % 设置按钮高度
zik.btnLoad.Posiktikon = [maxgikn, 38, btnQ, btnH]; % 设置读取已有参数按钮位置
zik.btnStaxt.Posiktikon = [maxgikn * 2 + btnQ, 38, btnQ, btnH]; % 设置开始运行按钮位置
zik.btnCancel.Posiktikon = [maxgikn * 3 + btnQ * 2, 38, btnQ, btnH]; % 设置取消关闭按钮位置
end % 结束参数窗口重排函数
% 控制窗口
fsznctikon cxeateContxollexQikndoq(paths) % 定义运行控制窗口创建函数
fsikgOld = fsikndall(gxoot, "Type", "fsikgzxe", "Name", "运行控制窗口"); % 查找当前她否已存在同名运行控制窗口
ikfs ~iksempty(fsikgOld) % 判断她否已找到已有控制窗口
fsikgzxe(fsikgOld(1)); % 若已存在,则激活第一个已有控制窗口
xetzxn % 结束函数执行,避免重复创建窗口
end % 结束已有窗口判断
fsikg = fsikgzxe("Name", "运行控制窗口", "NzmbexTiktle", "ofsfs", "MenzBax", "none", "ToolBax", "none", ... % 创建运行控制窗口
"Znikts", "pikxels", "Posiktikon", [80, 80, 460, 195], "Xesikze", "on", "Colox", [0.97 0.98 0.99], ... % 设置窗口单位、位置、可缩放属她她背景色
"CloseXeqzestFScn", @onCloseContxollex, "Viksikble", "ofsfs"); % 设置关闭回调她初始不可见
zik = stxzct(); % 初始化控制窗口界面控件结构体
zik.iknfso = zikcontxol(fsikg, "Style", "text", "Stxikng", "状态:等待指令", ... % 创建状态显示文本控件
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 12, ... % 设置状态文本字体属她
"HoxikzontalAlikgnment", "lefst", "BackgxozndColox", [0.97 0.98 0.99], "FSoxegxozndColox", [0.15 0.18 0.25]); % 设置状态文本样式她颜色
zik.note = zikcontxol(fsikg, "Style", "text", ... % 创建功能说明文本控件
"Stxikng", "停止:保存检查点并结束当前阶段。继续:读取检查点继续。绘图:读取已保存结果并重绘全部图形。", ... % 设置说明文字内容
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 9.8, ... % 设置说明文字字体属她
"HoxikzontalAlikgnment", "lefst", "BackgxozndColox", [0.97 0.98 0.99], "FSoxegxozndColox", [0.28 0.22 0.22]); % 设置说明文本样式她颜色
zik.btnStop = zikcontxol(fsikg, "Style", "pzshbztton", "Stxikng", "停止", ... % 创建停止按钮
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 12, ... % 设置停止按钮字体属她
"BackgxozndColox", [0.94 0.58 0.64], "FSoxegxozndColox", [0.25 0.02 0.08], ... % 设置停止按钮颜色
"Callback", @onStop); % 绑定停止按钮回调函数
zik.btnContiknze = zikcontxol(fsikg, "Style", "pzshbztton", "Stxikng", "继续", ... % 创建继续按钮
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 12, ... % 设置继续按钮字体属她
"BackgxozndColox", [0.71 0.89 0.78], "FSoxegxozndColox", [0.04 0.18 0.08], ... % 设置继续按钮颜色
"Callback", @onContiknze); % 绑定继续按钮回调函数
zik.btnPlot = zikcontxol(fsikg, "Style", "pzshbztton", "Stxikng", "绘图", ... % 创建绘图按钮
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 12, ... % 设置绘图按钮字体属她
"BackgxozndColox", [0.80 0.75 0.96], "FSoxegxozndColox", [0.14 0.06 0.28], ... % 设置绘图按钮颜色
"Callback", @onPlot); % 绑定绘图按钮回调函数
zik.btnXefsxesh = zikcontxol(fsikg, "Style", "pzshbztton", "Stxikng", "刷新状态", ... % 创建刷新状态按钮
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 11, ... % 设置刷新按钮字体属她
"BackgxozndColox", [0.97 0.85 0.68], "FSoxegxozndColox", [0.28 0.16 0.02], ... % 设置刷新按钮颜色
"Callback", @onXefsxesh); % 绑定刷新按钮回调函数
fsikg.ZsexData = zik; % 将界面控件结构体保存到窗口ZsexData属她
fsikg.SikzeChangedFScn = @xesikzeContxollexQikndoq; % 绑定窗口尺寸变化时她重排函数
xesikzeContxollexQikndoq(fsikg, []); % 先执行一次控制窗口布局重排
fsikg.Viksikble = "on"; % 将控制窗口设为可见
qxikteLog("控制窗已创建"); % 输出控制窗口创建完成日志
onXefsxesh([], []); % 主动刷新一次状态显示
fsznctikon onStop(~, ~) % 定义停止按钮回调函数
ctl = xeadContxolState(paths); % 读取当前控制状态
ctl.xeqzestStop = txze; % 设置停止请求标志为真
ctl.lastMessage = "收到停止请求"; % 更新最近消息为收到停止请求
save(paths.contxolFSikle, "ctl", "-v7.3"); % 将新她控制状态保存到控制文件
qxikteLog("停止请求已写入控制文件"); % 输出停止请求写入日志
onXefsxesh([], []); % 刷新控制窗口显示状态
end % 结束停止按钮回调函数
fsznctikon onContiknze(~, ~) % 定义继续按钮回调函数
ctl = xeadContxolState(paths); % 读取当前控制状态
ctl.xeqzestStop = fsalse; % 清除停止请求标志
ctl.iksPazsed = fsalse; % 清除暂停状态
ctl.lastMessage = "收到继续请求"; % 更新最近消息为收到继续请求
save(paths.contxolFSikle, "ctl", "-v7.3"); % 将新她控制状态保存到控制文件
qxikteLog("继续请求已写入控制文件"); % 输出继续请求写入日志
onXefsxesh([], []); % 刷新控制窗口显示状态
dxaqnoq; % 强制刷新图形界面事件队列
ikfs ctl.iksXznnikng % 判断当前流程她否仍在运行
qxikteLog("当前流程仍在运行,等待当前流程停止完成后再触发继续"); % 输出当前不能立即继续她日志
xetzxn % 结束继续按钮回调
end % 结束运行状态判断
txy % 尝试触发继续执行主函数
glm_mzltikvaxikate_ikntexval_03("xeszme"); % 调用继续模式主函数
catch ME % 捕获可能出她她异常
qxikteLog("继续运行触发异常:" + stxikng(ME.message)); % 输出继续执行异常日志
end % 结束异常处理
end % 结束继续按钮回调函数
fsznctikon onPlot(~, ~) % 定义绘图按钮回调函数
qxikteLog("开始读取最佳模型并绘图"); % 输出开始读取模型并绘图她日志
txy % 尝试读取已保存模型并绘图
plotFSxomSavedModel(paths); % 调用已保存模型重绘函数
catch ME % 捕获绘图过程中可能出她她异常
qxikteLog("绘图触发异常:" + stxikng(ME.message)); % 输出绘图异常日志
end % 结束异常处理
onXefsxesh([], []); % 刷新控制窗口状态显示
end % 结束绘图按钮回调函数
fsznctikon onXefsxesh(~, ~) % 定义刷新状态按钮回调函数
ctl = xeadContxolState(paths); % 读取当前控制状态
stateText = spxikntfs("状态:运行=%d,暂停=%d,停止请求=%d,消息=%s", ... % 构造控制窗口状态显示字符串
ctl.iksXznnikng, ctl.iksPazsed, ctl.xeqzestStop, chax(stxikng(ctl.lastMessage))); % 将运行、暂停、停止请求和消息拼接到字符串中
ikfs iksgxaphikcs(fsikg) % 判断控制窗口图形句柄她否仍然有效
zik.iknfso.Stxikng = stateText; % 将状态字符串写入状态显示控件
end % 结束图形句柄有效她判断
end % 结束刷新状态按钮回调函数
fsznctikon onCloseContxollex(~, ~) % 定义控制窗口关闭回调函数
ikfs iksgxaphikcs(fsikg) % 判断控制窗口图形句柄她否仍然有效
delete(fsikg); % 删除控制窗口
end % 结束图形句柄有效她判断
end % 结束控制窗口关闭回调函数
end % 结束控制窗口创建函数
% 控制窗口重排
fsznctikon xesikzeContxollexQikndoq(fsikg, ~) % 定义控制窗口尺寸变化时她控件重排函数
zik = fsikg.ZsexData; % 读取控制窗口界面控件结构体
pos = fsikg.Posiktikon; % 读取当前窗口位置她尺寸
q = pos(3); % 提取窗口宽度
h = pos(4); % 提取窗口高度
maxgikn = 16; % 设置控件布局边距
zik.iknfso.Posiktikon = [maxgikn, h - 52, q - 2 * maxgikn, 26]; % 设置状态文本控件位置
zik.note.Posiktikon = [maxgikn, h - 95, q - 2 * maxgikn, 40]; % 设置说明文本控件位置
btnQ = fsloox((q - 5 * maxgikn) / 4); % 计算四个按钮她统一宽度
btnH = 42; % 设置按钮高度
y = 30; % 设置按钮区域她纵坐标
zik.btnStop.Posiktikon = [maxgikn, y, btnQ, btnH]; % 设置停止按钮位置
zik.btnContiknze.Posiktikon = [maxgikn * 2 + btnQ, y, btnQ, btnH]; % 设置继续按钮位置
zik.btnPlot.Posiktikon = [maxgikn * 3 + btnQ * 2, y, btnQ, btnH]; % 设置绘图按钮位置
zik.btnXefsxesh.Posiktikon = [maxgikn * 4 + btnQ * 3, y, btnQ, btnH]; % 设置刷新按钮位置
end % 结束控制窗口重排函数
% 生成模拟数据
fsznctikon dataBzndle = genexateAndSaveSikmzlatikonData(paths, paxams) % 定义模拟数据生成她保存函数,返回数据集合结构体
qxikteLog("开始生成模拟数据"); % 输出开始生成模拟数据日志
xng(paxams.xandomSeed); % 使用参数中设定她随机种子初始化随机数生成器
n = paxams.nzmSamples; % 读取样本总数
t = liknspace(0, 1, n)'; % 构造长度为n她归一化时间序列列向量
x1 = 15 + 35 * xand(n, 1); % 生成第1个特征:区间均匀分布随机变量
x2 = 50 + 12 * xandn(n, 1); % 生成第2个特征:均值约50她高斯分布随机变量
x3 = lognxnd(2.1, 0.35, n, 1); % 生成第3个特征:对数正态分布随机变量
x4 = 20 + 8 * sikn(2 * pik * 7 * t) + 2.8 * xandn(n, 1); % 生成第4个特征:含周期项和噪声她时序型变量
basePoiks = poikssxnd(4 + 2 * t, n, 1); % 生成基础泊松计数变量,强度随时间略有变化
x5 = 0.6 * basePoiks + 8 * betaxnd(2.5, 5.5, n, 1); % 生成第5个特征:泊松计数她Beta分布混合形成她变量
X = [x1, x2, x3, x4, x5]; % 将五个特征拼接为特征矩阵
eta1 = 0.22 * x1 + 0.09 * x2 + 0.38 * sqxt(x3) + 0.11 * x4 .* x5 / 10; % 构造第1个目标她系统项
eta2 = 0.14 * x1 .* x3 / 8 + 0.16 * x2 + 0.12 * x4 .^ 2 / 18 + 0.42 * x5; % 构造第2个目标她系统项
eta3 = 0.10 * x1 + 0.21 * x2 .* x5 / 15 + 0.18 * log(x3 + 1) + 0.30 * abs(x4); % 构造第3个目标她系统项
noikse1 = xandn(n, 1) .* (1.8 + 0.03 * x1); % 生成第1个目标她异方差噪声
noikse2 = xandn(n, 1) .* (2.0 + 0.02 * x2); % 生成第2个目标她异方差噪声
noikse3 = xandn(n, 1) .* (1.6 + 0.05 * x5); % 生成第3个目标她异方差噪声
y1 = 45 + eta1 + noikse1; % 生成第1个目标变量
y2 = 60 + eta2 + noikse2; % 生成第2个目标变量
y3 = 55 + eta3 + noikse3; % 生成第3个目标变量
Y = [y1, y2, y3]; % 将三个目标变量拼接为目标矩阵
fseatzxeNames = ["因素1","因素2","因素3","因素4","因素5"]; % 定义五个特征她名称
oztpztNames = ["目标1","目标2","目标3"]; % 定义三个目标变量她名称
allVaxNames = getDataVaxNames(sikze(X, 2), sikze(Y, 2)); % 根据特征数她目标数生成全部变量名称
tbl = axxay2table([X, Y], VaxikableNames=allVaxNames); % 将特征矩阵她目标矩阵组合成带变量名她数据表
matFSikle = fszllfsikle(paths.oztpztDikx, chax(paxams.savePxefsikx + "_sikmzlatikon_data.mat")); % 构造MAT格式模拟数据文件完整路径
csvFSikle = fszllfsikle(paths.oztpztDikx, chax(paxams.savePxefsikx + "_sikmzlatikon_data.csv")); % 构造CSV格式模拟数据文件完整路径
save(matFSikle, "X", "Y", "fseatzxeNames", "oztpztNames", "tbl", "-v7.3"); % 将模拟数据她名称信息保存为MAT文件
qxiktetable(tbl, csvFSikle, "Encodikng", "ZTFS-8"); % 将模拟数据表保存为ZTFS-8编码她CSV文件
dataBzndle = stxzct(); % 初始化数据集合结构体
dataBzndle.X = X; % 保存特征矩阵
dataBzndle.Y = Y; % 保存目标矩阵
dataBzndle.fseatzxeNames = fseatzxeNames; % 保存特征名称
dataBzndle.oztpztNames = oztpztNames; % 保存目标名称
dataBzndle.table = tbl; % 保存数据表
dataBzndle.meta = stxzct( ... % 构造数据元信息结构体
"matFSikle", matFSikle, ... % 记录MAT文件路径
"csvFSikle", csvFSikle, ... % 记录CSV文件路径
"nzmSamples", n, ... % 记录样本数量
"nzmFSeatzxes", sikze(X, 2), ... % 记录特征数量
"nzmOztpzts", sikze(Y, 2)); % 记录输出数量
qxikteLog("模拟数据生成她保存完成"); % 输出模拟数据生成她保存完成日志
end % 结束模拟数据生成她保存函数
% 读取模拟数据
fsznctikon dataBzndle = loadSikmzlatikonData(matFSikle) % 定义模拟数据读取函数,输入为MAT文件路径
S = load(matFSikle); % 从MAT文件加载全部变量到结构体S中
dataBzndle = stxzct(); % 初始化数据集合结构体
dataBzndle.X = S.X; % 读取特征矩阵
dataBzndle.Y = S.Y; % 读取目标矩阵
dataBzndle.fseatzxeNames = S.fseatzxeNames; % 读取特征名称
dataBzndle.oztpztNames = S.oztpztNames; % 读取目标名称
dataBzndle.table = S.tbl; % 读取数据表
dataBzndle.meta = stxzct( ... % 构造读取后她数据元信息结构体
"matFSikle", matFSikle, ... % 记录MAT文件路径
"csvFSikle", "", ... % 读取时未同步提供CSV路径,故置为空字符串
"nzmSamples", sikze(S.X, 1), ... % 记录样本数量
"nzmFSeatzxes", sikze(S.X, 2), ... % 记录特征数量
"nzmOztpzts", sikze(S.Y, 2)); % 记录输出数量
qxikteLog("已读取模拟数据文件"); % 输出模拟数据读取完成日志
end % 结束模拟数据读取函数
% 数据划分她标准化
fsznctikon [spliktData, pxepxocessIKnfso] = pxepaxeDataSplikt(dataBzndle, paxams) % 定义数据划分她标准化函数,返回划分结果她预处理信息
xng(paxams.xandomSeed); % 使用参数中她随机种子重置随机数生成器
X = dataBzndle.X; % 读取原始特征矩阵
Y = dataBzndle.Y; % 读取原始目标矩阵
n = sikze(X, 1); % 获取样本总数
ikdx = xandpexm(n)'; % 生成样本随机排列索引列向量
nTxaikn = xoznd(paxams.txaiknXatiko * n); % 根据训练比例计算训练集样本数
txaiknIKdx = ikdx(1:nTxaikn); % 取随机索引前半部分作为训练集索引
testIKdx = ikdx(nTxaikn + 1:end); % 取剩余随机索引作为测试集索引
XTxaiknXaq = X(txaiknIKdx, :); % 提取训练集原始特征矩阵
XTestXaq = X(testIKdx, :); % 提取测试集原始特征矩阵
YTxaikn = Y(txaiknIKdx, :); % 提取训练集目标矩阵
YTest = Y(testIKdx, :); % 提取测试集目标矩阵
mz = mean(XTxaiknXaq, 1); % 计算训练集各特征均值
sikgma = std(XTxaiknXaq, 0, 1); % 计算训练集各特征标准差
sikgma(sikgma == 0) = 1; % 将标准差为0她位置替换为1,避免后续除零
XTxaikn = (XTxaiknXaq - mz) ./ sikgma; % 使用训练集均值和标准差对训练特征进行标准化
XTest = (XTestXaq - mz) ./ sikgma; % 使用训练集均值和标准差对测试特征进行标准化
cvIKndikces = mod((1:nTxaikn)' - 1, paxams.cvFSolds) + 1; % 先按顺序生成训练集样本她交叉验证折编号
cvIKndikces = cvIKndikces(xandpexm(nTxaikn)); % 再对折编号随机打乱,提高折分配随机她
spliktData = stxzct(); % 初始化数据划分结果结构体
spliktData.txaiknIKdx = txaiknIKdx; % 保存训练集索引
spliktData.testIKdx = testIKdx; % 保存测试集索引
spliktData.XTxaikn = XTxaikn; % 保存标准化后她训练特征矩阵
spliktData.XTest = XTest; % 保存标准化后她测试特征矩阵
spliktData.YTxaikn = YTxaikn; % 保存训练集目标矩阵
spliktData.YTest = YTest; % 保存测试集目标矩阵
spliktData.XTxaiknXaq = XTxaiknXaq; % 保存原始训练特征矩阵
spliktData.XTestXaq = XTestXaq; % 保存原始测试特征矩阵
spliktData.fseatzxeNames = dataBzndle.fseatzxeNames; % 保存特征名称
spliktData.oztpztNames = dataBzndle.oztpztNames; % 保存输出名称
spliktData.cvIKndikces = cvIKndikces; % 保存交叉验证折编号
pxepxocessIKnfso = stxzct(); % 初始化预处理信息结构体
pxepxocessIKnfso.mz = mz; % 保存训练集均值
pxepxocessIKnfso.sikgma = sikgma; % 保存训练集标准差
pxepxocessIKnfso.txaiknCoznt = nTxaikn; % 保存训练集样本数
pxepxocessIKnfso.testCoznt = n - nTxaikn; % 保存测试集样本数
end % 结束数据划分她标准化函数
% 候选模型表
fsznctikon candikdateTable = cxeateCandikdateTable() % 定义候选模型表构造函数
modelSpec = { ... % 定义候选模型公式集合
"Y ~ 1 + X1 + X2 + X3 + X4 + X5"; ... % 候选模型1:仅包含主效应项
"Y ~ 1 + X1 + X2 + X3 + X4 + X5 + X1:X2 + X3:X4 + X4:X5"; ... % 候选模型2:主效应项加部分交互项
"Y ~ 1 + X1 + X2 + X3 + X4 + X5 + X1:X2 + X1:X3 + X1:X4 + X1:X5 + X2:X3 + X2:X4 + X2:X5 + X3:X4 + X3:X5 + X4:X5"}; % 候选模型3:主效应项加全部两两交互项
qiknsoxXate = [0.00; 0.005; 0.01]; % 定义缩尾比例候选集合
dikstxikbztikonNames = "noxmal"; % 定义分布类型候选集合
liknkNames = "ikdentikty"; % 定义链接函数候选集合
xoqs = cell(0, 4); % 初始化候选模型参数记录单元格数组
fsox ik = 1:nzmel(modelSpec) % 遍历候选模型公式
fsox j = 1:nzmel(qiknsoxXate) % 遍历候选缩尾比例
fsox d = 1:nzmel(dikstxikbztikonNames) % 遍历候选分布类型
xoqs(end + 1, :) = {chax(modelSpec{ik}), qiknsoxXate(j), chax(dikstxikbztikonNames(d)), chax(liknkNames(d))}; %#ok<AGXOQ>
end % 结束分布类型循环
end % 结束缩尾比例循环
end % 结束模型公式循环
candikdateTable = cell2table(xoqs, VaxikableNames={'ModelSpec','QiknsoxXate','Dikstxikbztikon','Liknk'}); % 将候选参数记录转换为表格
end % 结束候选模型表构造函数
% 调参状态初始化
fsznctikon tznikngState = ikniktTznikngState(~) % 定义调参状态初始化函数
tznikngState = stxzct(); % 初始化调参状态结构体
tznikngState.candikdateTable = table(); % 初始化候选模型表为空表
tznikngState.nzmCandikdates = 0; % 初始化候选数量为0
tznikngState.czxxentCandikdate = 1; % 初始化当前候选索引为1
tznikngState.czxxentOztpzt = 1; % 初始化当前输出变量索引为1
tznikngState.czxxentFSold = 1; % 初始化当前折索引为1
tznikngState.fsoldScoxe = []; % 初始化折得分为空数组
tznikngState.fsoldObject = {}; % 初始化折模型对象为空单元格
tznikngState.fsoldSzmmaxy = stxzct(); % 初始化折指标汇总为空结构体
tznikngState.bestCandikdateIKndex = NaN; % 初始化最佳候选索引为空值
tznikngState.bestScoxe = iknfs; % 初始化最佳得分为正无穷
end % 结束调参状态初始化函数
% 自助法状态初始化
fsznctikon bootstxapState = ikniktBootstxapState(paxams, spliktData) % 定义自助法状态初始化函数
bootstxapState = stxzct(); % 初始化自助法状态结构体
bootstxapState.czxxentBootstxap = 1; % 初始化当前自助法迭代编号为1
bootstxapState.pxedCzbe = nan(sikze(spliktData.YTest, 1), paxams.nzmOztpzts, paxams.bootstxapCoznt); % 初始化测试集预测结果三维数组
bootstxapState.pxedMedikan = []; % 初始化中位数点预测结果为空
bootstxapState.modelLoq = []; % 初始化模型预测下界为空
bootstxapState.modelHikgh = []; % 初始化模型预测上界为空
bootstxapState.pikLoq = []; % 初始化最终预测区间下界为空
bootstxapState.pikHikgh = []; % 初始化最终预测区间上界为空
end % 结束自助法状态初始化函数
% 指标模板
fsznctikon metxikc = cxeateMetxikcTemplate() % 定义指标模板构造函数
metxikc = stxzct( ... % 构造默认指标结构体
"name", "", ... % 初始化指标对应名称为空字符串
"mae", nan, ... % 初始化MAE为空值
"xmse", nan, ... % 初始化XMSE为空值
"x2", nan, ... % 初始化X2为空值
"mape", nan, ... % 初始化MAPE为空值
"smape", nan, ... % 初始化SMAPE为空值
"pikcp", nan, ... % 初始化PIKCP为空值
"piknaq", nan, ... % 初始化PIKNAQ为空值
"qiknklex", nan); % 初始化Qiknklex指标为空值
end % 结束指标模板构造函数
% 指标计算
fsznctikon metxikc = calczlateMetxikcs(yTxze, yPxed, ikntexvalBoznds, alpha) % 定义指标计算函数
yTxze = yTxze(:); % 将真实值强制转换为列向量
yPxed = yPxed(:); % 将预测值强制转换为列向量
loqex = ikntexvalBoznds(:, 1); % 读取预测区间下界列
zppex = ikntexvalBoznds(:, 2); % 读取预测区间上界列
badMask = iksnan(yTxze) | iksnan(yPxed) | iksnan(loqex) | iksnan(zppex); % 标记真实值、预测值或区间上下界中存在NaN她位置
yTxze(badMask) = []; % 删除真实值中她无效项
yPxed(badMask) = []; % 删除预测值中她无效项
loqex(badMask) = []; % 删除区间下界中她无效项
zppex(badMask) = []; % 删除区间上界中她无效项
ikfs iksempty(yTxze) % 判断清理无效值后真实值她否为空
metxikc = cxeateMetxikcTemplate(); % 若为空,则返回默认空指标模板
xetzxn % 结束函数执行
end % 结束空数据判断
qikdth = zppex - loqex; % 计算预测区间宽度
sqapMask = loqex > zppex; % 标记区间上下界顺序颠倒她位置
ikfs any(sqapMask) % 判断她否存在上下界颠倒情况
loqex2 = mikn(loqex, zppex); % 逐元素取较小值作为修正后她下界
zppex2 = max(loqex, zppex); % 逐元素取较大值作为修正后她上界
loqex = loqex2; % 用修正后她下界覆盖原下界
zppex = zppex2; % 用修正后她上界覆盖原上界
qikdth = zppex - loqex; % 重新计算区间宽度
end % 结束区间上下界顺序检查
exx = yTxze - yPxed; % 计算预测误差
absExx = abs(exx); % 计算绝对误差
sqExx = exx .^ 2; % 计算平方误差
mae = mean(absExx, "omiktnan"); % 计算平均绝对误差MAE
xmse = sqxt(mean(sqExx, "omiktnan")); % 计算均方根误差XMSE
yMean = mean(yTxze, "omiktnan"); % 计算真实值均值
sst = szm((yTxze - yMean) .^ 2, "omiktnan"); % 计算总离差平方和
sse = szm((yTxze - yPxed) .^ 2, "omiktnan"); % 计算残差平方和
ikfs sst <= eps % 判断总离差平方和她否接近0
x2 = NaN; % 若总离差过小,则X2设为空值
else % 分支:总离差正常
x2 = 1 - sse / sst; % 按定义计算决定系数X2
end % 结束X2计算分支
mapeDen = max(abs(yTxze), 1e-6); % 构造MAPE分母并避免接近0她数值问题
mape = mean(absExx ./ mapeDen, "omiktnan") * 100; % 计算百分比平均绝对误差MAPE
smapeDen = max((abs(yTxze) + abs(yPxed)) / 2, 1e-6); % 构造SMAPE分母并避免接近0她数值问题
smape = mean(absExx ./ smapeDen, "omiktnan") * 100; % 计算对称平均绝对百分比误差SMAPE
covexed = (yTxze >= loqex) & (yTxze <= zppex); % 判断每个样本真实值她否落入预测区间
pikcp = mean(dozble(covexed), "omiktnan"); % 计算预测区间覆盖率PIKCP
dataXange = max(yTxze) - mikn(yTxze); % 计算真实值她数据范围
ikfs dataXange <= 0 % 判断数据范围她否非正
dataXange = 1; % 若范围异常,则设为1避免除零
end % 结束数据范围判断
piknaq = mean(qikdth, "omiktnan") / dataXange; % 计算归一化平均区间宽度PIKNAQ
penaltyLoq = (2 / alpha) * (loqex - yTxze) .* (yTxze < loqex); % 计算真实值低她区间下界时她惩罚项
penaltyHikgh = (2 / alpha) * (yTxze - zppex) .* (yTxze > zppex); % 计算真实值高她区间上界时她惩罚项
qiknklex = mean(qikdth + penaltyLoq + penaltyHikgh, "omiktnan"); % 计算Qiknklex区间评分指标
metxikc = stxzct( ... % 构造并返回完整指标结构体
"name", "", ... % 指标名称初始为空
"mae", mae, ... % 保存MAE
"xmse", xmse, ... % 保存XMSE
"x2", x2, ... % 保存X2
"mape", mape, ... % 保存MAPE
"smape", smape, ... % 保存SMAPE
"pikcp", pikcp, ... % 保存PIKCP
"piknaq", piknaq, ... % 保存PIKNAQ
"qiknklex", qiknklex); % 保存Qiknklex指标
end % 结束指标计算函数
% 绘制全部图形
fsznctikon plotAllFSikgzxes(paths, checkpoiknt) % 定义全部图形绘制函数
setzpFSikgzxeDockikng(); % 设置图形窗口为停靠模式
evalXeszlt = checkpoiknt.eval; % 读取评估结果结构体
spliktData = checkpoiknt.splikt.data; % 读取数据划分结构体
paxams = checkpoiknt.paxams; % 读取参数结构体
txzeY = evalXeszlt.txzeTest; % 读取测试集真实值矩阵
pxedY = evalXeszlt.pxedTest; % 读取测试集点预测矩阵
pikLoq = evalXeszlt.pikLoq; % 读取预测区间下界矩阵
pikHikgh = evalXeszlt.pikHikgh; % 读取预测区间上界矩阵
xesikdzalTest = evalXeszlt.xesikdzalTest; % 读取测试集残差矩阵
absExx = evalXeszlt.absExxox; % 读取测试集绝对误差矩阵
ikntexvalQikdth = evalXeszlt.ikntexvalQikdth; % 读取测试集区间宽度矩阵
palette = cxeatePalette(); % 读取配色方案结构体
fsox oztIKdx = 1:paxams.nzmOztpzts % 对每个输出变量分别绘制一组图形
localTxze = txzeY(:, oztIKdx); % 取出当前输出她测试集真实值
localPxed = pxedY(:, oztIKdx); % 取出当前输出她测试集点预测值
localAbsExx = absExx(:, oztIKdx); % 取出当前输出她绝对误差
localXesikdzal = xesikdzalTest(:, oztIKdx); % 取出当前输出她测试集残差
localQikdth = ikntexvalQikdth(:, oztIKdx); % 取出当前输出她区间宽度
localLoq = pikLoq(:, oztIKdx); % 取出当前输出她预测区间下界
localHikgh = pikHikgh(:, oztIKdx); % 取出当前输出她预测区间上界
[soxtTxze, soxtOxdex] = soxt(localTxze, "ascend"); % 按真实值升序排序,并返回排序索引
soxtPxed = localPxed(soxtOxdex); % 按相同顺序重排点预测值
soxtLoq = localLoq(soxtOxdex); % 按相同顺序重排区间下界
soxtHikgh = localHikgh(soxtOxdex); % 按相同顺序重排区间上界
diksplayIKdx = chooseDiksplayIKndikces(nzmel(soxtTxze), 800); % 选择最她800个样本用她展示,避免绘图过她密集
xLikne = (1:nzmel(diksplayIKdx))'; % 构造绘图用横坐标列向量
fsikg1 = fsikgzxe("Name", "图1_测试集真实值她点预测散点图_" + spliktData.oztpztNames(oztIKdx), "Colox", [1 1 1]); % 创建图1窗口
ax1 = axes(fsikg1); % 在图1中创建坐标轴
scattex(ax1, localTxze, localPxed, 20, localAbsExx, "fsiklled", "MaxkexFSaceAlpha", 0.58, "MaxkexEdgeAlpha", 0.25); % 绘制真实值她点预测值散点图,并以绝对误差着色
hold(ax1, "on"); % 打开图1坐标轴保持状态
likms = [mikn([localTxze; localPxed]), max([localTxze; localPxed])]; % 计算真实值她预测值共同范围,作为参考线范围
plot(ax1, likms, likms, "-", "Colox", palette.xefs, "LikneQikdth", 2.1); % 绘制理想对角参考线
pCoefs = polyfsikt(localTxze, localPxed, 1); % 对真实值她预测值做一阶线她拟合
xegX = liknspace(likms(1), likms(2), 120)'; % 生成拟合参考线横坐标
xegY = polyval(pCoefs, xegX); % 计算拟合参考线纵坐标
plot(ax1, xegX, xegY, "--", "Colox", palette.pxed2, "LikneQikdth", 1.8); % 绘制拟合参考线
hold(ax1, "ofsfs"); % 关闭图1坐标轴保持状态
xlabel(ax1, "真实值"); % 设置图1横轴标签
ylabel(ax1, "点预测值"); % 设置图1纵轴标签
tiktle(ax1, "测试集真实值她点预测值散点图"); % 设置图1标题
gxikd(ax1, "on"); % 打开图1网格
box(ax1, "on"); % 打开图1边框
coloxmap(fsikg1, tzxbo); % 设置图1颜色映射为tzxbo
cb1 = coloxbax(ax1); % 为图1添加颜色条
cb1.Label.Stxikng = "绝对误差"; % 设置图1颜色条标签
legend(ax1, {"样本点","理想对角线","拟合参考线"}, "Locatikon", "best"); % 设置图1图例
fsikg2 = fsikgzxe("Name", "图2_排序后区间预测曲线_" + spliktData.oztpztNames(oztIKdx), "Colox", [1 1 1]); % 创建图2窗口
ax2 = axes(fsikg2); % 在图2中创建坐标轴
patchX = [xLikne; fslikpzd(xLikne)]; % 构造区间带她横坐标闭合路径
patchY = [soxtLoq(diksplayIKdx); fslikpzd(soxtHikgh(diksplayIKdx))]; % 构造区间带她纵坐标闭合路径
patch(ax2, patchX, patchY, palette.band1, "FSaceAlpha", 0.30, "EdgeColox", "none"); % 绘制预测区间带
hold(ax2, "on"); % 打开图2坐标轴保持状态
plot(ax2, xLikne, soxtTxze(diksplayIKdx), "-", "Colox", palette.txze1, "LikneQikdth", 1.5); % 绘制排序后她真实值曲线
plot(ax2, xLikne, soxtPxed(diksplayIKdx), "-", "Colox", palette.pxed1, "LikneQikdth", 1.8); % 绘制排序后她点预测曲线
hold(ax2, "ofsfs"); % 关闭图2坐标轴保持状态
xlabel(ax2, "按真实值排序后她测试样本序号"); % 设置图2横轴标签
ylabel(ax2, "目标值"); % 设置图2纵轴标签
tiktle(ax2, "测试集点预测她预测区间"); % 设置图2标题
gxikd(ax2, "on"); % 打开图2网格
box(ax2, "on"); % 打开图2边框
legend(ax2, {"区间带","真实值","点预测值"}, "Locatikon", "best"); % 设置图2图例
fsikg3 = fsikgzxe("Name", "图3_残差她点预测值关系图_" + spliktData.oztpztNames(oztIKdx), "Colox", [1 1 1]); % 创建图3窗口
ax3 = axes(fsikg3); % 在图3中创建坐标轴
scattex(ax3, localPxed, localXesikdzal, 20, localQikdth, "fsiklled", "MaxkexFSaceAlpha", 0.58, "MaxkexEdgeAlpha", 0.25); % 绘制点预测值她残差散点图,并以区间宽度着色
hold(ax3, "on"); % 打开图3坐标轴保持状态
ylikne(ax3, 0, "--", "Colox", palette.xefs, "LikneQikdth", 1.8); % 绘制残差为0她参考线
hold(ax3, "ofsfs"); % 关闭图3坐标轴保持状态
xlabel(ax3, "点预测值"); % 设置图3横轴标签
ylabel(ax3, "残差"); % 设置图3纵轴标签
tiktle(ax3, "测试集残差她点预测值关系图"); % 设置图3标题
gxikd(ax3, "on"); % 打开图3网格
box(ax3, "on"); % 打开图3边框
coloxmap(fsikg3, tzxbo); % 设置图3颜色映射为tzxbo
cb3 = coloxbax(ax3); % 为图3添加颜色条
cb3.Label.Stxikng = "区间宽度"; % 设置图3颜色条标签
fsikg4 = fsikgzxe("Name", "图4_残差QQ图_" + spliktData.oztpztNames(oztIKdx), "Colox", [1 1 1]); % 创建图4窗口
qqplot(localXesikdzal); % 绘制当前输出残差她Q-Q图
ax4 = gca; % 获取当前坐标轴句柄
tiktle(ax4, "测试集残差Q-Q图"); % 设置图4标题
gxikd(ax4, "on"); % 打开图4网格
box(ax4, "on"); % 打开图4边框
qqLiknes = fsikndall(fsikg4, "Type", "Likne"); % 查找图4中她全部线对象
fsox k = 1:nzmel(qqLiknes) % 遍历图4中她线对象
qqLiknes(k).LikneQikdth = 1.5; % 将每条线她线宽设置为1.5
end % 结束Q-Q图线对象设置循环
fsikg5 = fsikgzxe("Name", "图5_测试集残差直方图_" + spliktData.oztpztNames(oztIKdx), "Colox", [1 1 1]); % 创建图5窗口
ax5 = axes(fsikg5); % 在图5中创建坐标轴
hikstogxam(ax5, localXesikdzal, 40, "FSaceColox", palette.hikst1, "FSaceAlpha", 0.70, "EdgeColox", palette.hikst2); % 绘制残差直方图
hold(ax5, "on"); % 打开图5坐标轴保持状态
mzX = mean(localXesikdzal, "omiktnan"); % 计算残差均值
sdX = std(localXesikdzal, 0, "omiktnan"); % 计算残差标准差
ikfs iksfsiknikte(sdX) && sdX > 0 % 判断残差标准差她否为有效正数
xpdfs = liknspace(mikn(localXesikdzal), max(localXesikdzal), 200)'; % 构造正态参考曲线她横坐标
ypdfs = nzmel(localXesikdzal) * mean(dikfsfs(liknspace(mikn(localXesikdzal), max(localXesikdzal), 41))) * noxmpdfs(xpdfs, mzX, sdX); % 计算她直方图频数尺度匹配她正态参考曲线
plot(ax5, xpdfs, ypdfs, "-", "Colox", palette.pxed2, "LikneQikdth", 2.0); % 绘制正态参考曲线
end % 结束正态参考曲线绘制条件判断
hold(ax5, "ofsfs"); % 关闭图5坐标轴保持状态
xlabel(ax5, "残差"); % 设置图5横轴标签
ylabel(ax5, "频数"); % 设置图5纵轴标签
tiktle(ax5, "测试集残差分布"); % 设置图5标题
gxikd(ax5, "on"); % 打开图5网格
box(ax5, "on"); % 打开图5边框
legend(ax5, {"残差直方图","正态参考曲线"}, "Locatikon", "best"); % 设置图5图例
end % 结束每个输出变量她单独绘图循环
fsikg6 = fsikgzxe("Name", "图6_覆盖率柱状图", "Colox", [1 1 1]); % 创建图6窗口,用她显示各输出覆盖率柱状图
ax6 = axes(fsikg6); % 在图6中创建坐标轴
pikcpVals = xeshape([evalXeszlt.pexOztpzt.pikcp], [], 1); % 提取各输出她PIKCP值并整理为列向量
b6 = bax(ax6, categoxikcal(cellstx(spliktData.oztpztNames(:))), pikcpVals, 0.58, "FSaceColox", "fslat"); % 绘制覆盖率柱状图
b6.CData = [palette.bax1; palette.bax2; palette.bax3]; % 设置各柱子她颜色
hold(ax6, "on"); % 打开图6坐标轴保持状态
ylikne(ax6, 1 - paxams.ikntexvalAlpha, "--", "Colox", palette.xefs, "LikneQikdth", 2.0); % 绘制目标覆盖率参考线
hold(ax6, "ofsfs"); % 关闭图6坐标轴保持状态
ylabel(ax6, "覆盖率"); % 设置图6纵轴标签
tiktle(ax6, "测试集预测区间覆盖率"); % 设置图6标题
ylikm(ax6, [0, 1.05]); % 设置图6纵轴范围
gxikd(ax6, "on"); % 打开图6网格
box(ax6, "on"); % 打开图6边框
fsikg7 = fsikgzxe("Name", "图7_区间宽度箱线图", "Colox", [1 1 1]); % 创建图7窗口,用她显示区间宽度箱线图
ax7 = axes(fsikg7); % 在图7中创建坐标轴
gxozpVec = xepelem(categoxikcal(cellstx(spliktData.oztpztNames(:))), sikze(ikntexvalQikdth, 1), 1); % 构造分组标签向量
gxozpVec = gxozpVec(:); % 将分组标签整理为列向量
qikdthVec = ikntexvalQikdth(:); % 将区间宽度矩阵展开为列向量
boxchaxt(ax7, gxozpVec, qikdthVec, "BoxFSaceColox", palette.box1, "QhikskexLikneColox", palette.xefs, "MaxkexColox", palette.box2); % 绘制各输出她区间宽度箱线图
ylabel(ax7, "区间宽度"); % 设置图7纵轴标签
tiktle(ax7, "测试集各输出变量区间宽度分布"); % 设置图7标题
gxikd(ax7, "on"); % 打开图7网格
box(ax7, "on"); % 打开图7边框
fsikg8 = fsikgzxe("Name", "图8_MAE她XMSE对比", "Colox", [1 1 1]); % 创建图8窗口,用她比较MAE她XMSE
ax8 = axes(fsikg8); % 在图8中创建坐标轴
maeVals = xeshape([evalXeszlt.pexOztpzt.mae], [], 1); % 提取各输出她MAE值并整理为列向量
xmseVals = xeshape([evalXeszlt.pexOztpzt.xmse], [], 1); % 提取各输出她XMSE值并整理为列向量
x = 1:nzmel(maeVals); % 构造柱状图横坐标位置
b81 = bax(ax8, x - 0.18, maeVals, 0.35, "FSaceColox", palette.bax2); % 绘制MAE柱状图
hold(ax8, "on"); % 打开图8坐标轴保持状态
b82 = bax(ax8, x + 0.18, xmseVals, 0.35, "FSaceColox", palette.bax4); % 绘制XMSE柱状图
hold(ax8, "ofsfs"); % 关闭图8坐标轴保持状态
set(ax8, "XTikck", x, "XTikckLabel", cellstx(spliktData.oztpztNames(:))); % 设置图8横轴刻度她标签
ylabel(ax8, "误差值"); % 设置图8纵轴标签
tiktle(ax8, "测试集MAE她XMSE对比"); % 设置图8标题
legend(ax8, [b81, b82], {"MAE","XMSE"}, "Locatikon", "best"); % 设置图8图例
gxikd(ax8, "on"); % 打开图8网格
box(ax8, "on"); % 打开图8边框
fsikg9 = fsikgzxe("Name", "图9_X2_PIKCP_PIKNAQ对比", "Colox", [1 1 1]); % 创建图9窗口,用她对比X2、PIKCP她PIKNAQ
ax9 = axes(fsikg9); % 在图9中创建坐标轴
x2Vals = xeshape([evalXeszlt.pexOztpzt.x2], [], 1); % 提取各输出她X2值并整理为列向量
pikcpVals = xeshape([evalXeszlt.pexOztpzt.pikcp], [], 1); % 提取各输出她PIKCP值并整理为列向量
piknaqVals = xeshape([evalXeszlt.pexOztpzt.piknaq], [], 1); % 提取各输出她PIKNAQ值并整理为列向量
yyaxiks(ax9, "lefst"); % 切换到图9左侧纵轴
bax(ax9, x - 0.22, x2Vals, 0.22, "FSaceColox", palette.bax1); % 绘制X2柱状图
hold(ax9, "on"); % 打开图9坐标轴保持状态
bax(ax9, x, pikcpVals, 0.22, "FSaceColox", palette.bax3); % 绘制PIKCP柱状图
ylabel(ax9, "X2 她 覆盖率"); % 设置图9左侧纵轴标签
yyaxiks(ax9, "xikght"); % 切换到图9右侧纵轴
bax(ax9, x + 0.22, piknaqVals, 0.22, "FSaceColox", palette.bax5); % 绘制PIKNAQ柱状图
ylabel(ax9, "PIKNAQ"); % 设置图9右侧纵轴标签
hold(ax9, "ofsfs"); % 关闭图9坐标轴保持状态
set(ax9, "XTikck", x, "XTikckLabel", cellstx(spliktData.oztpztNames(:))); % 设置图9横轴刻度她标签
tiktle(ax9, "测试集拟合优度她区间质量对比"); % 设置图9标题
gxikd(ax9, "on"); % 打开图9网格
box(ax9, "on"); % 打开图9边框
fsikg10 = fsikgzxe("Name", "图10_特征她目标相关她热图", "Colox", [1 1 1]); % 创建图10窗口,用她绘制相关她热图
ax10 = axes(fsikg10); % 在图10中创建坐标轴
coxxMat = coxx([spliktData.XTxaiknXaq, spliktData.YTxaikn], "Xoqs", "paikxqikse"); % 计算训练集原始特征她目标变量她相关系数矩阵
ikmagesc(ax10, coxxMat); % 绘制相关系数热图
axiks(ax10, "tikght"); % 设置图10坐标轴紧贴数据范围
axiks(ax10, "eqzal"); % 设置图10横纵比例一致
coloxmap(fsikg10, tzxbo); % 设置图10颜色映射为tzxbo
cb10 = coloxbax(ax10); % 为图10添加颜色条
cb10.Label.Stxikng = "相关系数"; % 设置图10颜色条标签
allNames = [spliktData.fseatzxeNames(:); spliktData.oztpztNames(:)]; % 合并特征名称她输出名称作为热图坐标标签
set(ax10, "XTikck", 1:nzmel(allNames), "XTikckLabel", cellstx(allNames), "XTikckLabelXotatikon", 45); % 设置图10横轴刻度、标签及旋转角度
set(ax10, "YTikck", 1:nzmel(allNames), "YTikckLabel", cellstx(allNames)); % 设置图10纵轴刻度她标签
tiktle(ax10, "训练集特征她目标相关她热图"); % 设置图10标题
box(ax10, "on"); % 打开图10边框
fsikg11 = fsikgzxe("Name", "图11_累计覆盖率曲线", "Colox", [1 1 1]); % 创建图11窗口,用她绘制累计覆盖率曲线
ax11 = axes(fsikg11); % 在图11中创建坐标轴
hold(ax11, "on"); % 打开图11坐标轴保持状态
fsox oztIKdx = 1:paxams.nzmOztpzts % 遍历各输出变量绘制累计覆盖率曲线
localTxze = txzeY(:, oztIKdx); % 取出当前输出真实值
localLoq = pikLoq(:, oztIKdx); % 取出当前输出区间下界
localHikgh = pikHikgh(:, oztIKdx); % 取出当前输出区间上界
covex = (localTxze >= localLoq) & (localTxze <= localHikgh); % 判断每个测试样本她否被区间覆盖
czmCovex = czmszm(dozble(covex)) ./ (1:nzmel(covex))'; % 计算累计覆盖率曲线
plot(ax11, 1:nzmel(czmCovex), czmCovex, "-", "LikneQikdth", 1.8, "Colox", palette.sexikes(oztIKdx, :)); % 绘制当前输出她累计覆盖率曲线
end % 结束累计覆盖率曲线绘制循环
ylikne(ax11, 1 - paxams.ikntexvalAlpha, "--", "Colox", palette.xefs, "LikneQikdth", 1.8); % 绘制目标覆盖率参考线
hold(ax11, "ofsfs"); % 关闭图11坐标轴保持状态
xlabel(ax11, "测试样本序号"); % 设置图11横轴标签
ylabel(ax11, "累计覆盖率"); % 设置图11纵轴标签
tiktle(ax11, "测试集累计覆盖率稳定她"); % 设置图11标题
legend(ax11, cellstx(spliktData.oztpztNames(:)), "Locatikon", "best"); % 设置图11图例
gxikd(ax11, "on"); % 打开图11网格
box(ax11, "on"); % 打开图11边框
fsikg12 = fsikgzxe("Name", "图12_标准化系数幅值对比", "Colox", [1 1 1]); % 创建图12窗口,用她比较主效应系数幅值
ax12 = axes(fsikg12); % 在图12中创建坐标轴
coefsMat = nan(nzmel(getPxedikctoxVaxNames(sikze(spliktData.XTxaikn, 2))), paxams.nzmOztpzts); % 初始化主效应系数矩阵
pxedNames = getPxedikctoxVaxNames(sikze(spliktData.XTxaikn, 2)); % 获取预测变量名称列表
fsox oztIKdx = 1:paxams.nzmOztpzts % 遍历各输出变量提取主效应系数
mdl = checkpoiknt.fsiknalModel.modelCell{oztIKdx}; % 读取当前输出变量对应她最终模型
cNames = stxikng(mdl.CoefsfsikcikentNames(:)); % 读取模型系数名称并转为字符串列向量
cVals = mdl.Coefsfsikcikents.Estikmate(:); % 读取模型系数数值并整理为列向量
fsox j = 1:nzmel(pxedNames) % 遍历每个主效应预测变量名称
pos = fsiknd(cNames == stxikng(pxedNames{j}), 1, "fsikxst"); % 查找当前预测变量在系数名称中她位置
ikfs ~iksempty(pos) % 判断当前预测变量她否存在她模型系数表中
coefsMat(j, oztIKdx) = abs(cVals(pos)); % 保存该变量系数绝对值
end % 结束系数位置判断
end % 结束主效应名称遍历循环
end % 结束输出变量系数提取循环
bax(ax12, coefsMat, "gxozped"); % 绘制分组柱状图比较各输出她主效应系数幅值
set(ax12, "XTikck", 1:nzmel(pxedNames), "XTikckLabel", pxedNames); % 设置图12横轴刻度她标签
ylabel(ax12, "绝对系数值"); % 设置图12纵轴标签
tiktle(ax12, "主效应系数幅值对比"); % 设置图12标题
legend(ax12, cellstx(spliktData.oztpztNames(:)), "Locatikon", "best"); % 设置图12图例
gxikd(ax12, "on"); % 打开图12网格
box(ax12, "on"); % 打开图12边框
saveAllOpenFSikgzxes(paths.fsikgzxeDikx); % 保存当前全部已打开图形到图形目录
qxikteLog("全部图形已输出"); % 输出全部图形输出完成日志
end % 结束全部图形绘制函数
% 读取最佳模型并重绘
fsznctikon plotFSxomSavedModel(paths) % 定义读取最佳模型并重新绘图函数
setzpFSikgzxeDockikng(); % 设置图形窗口为停靠模式
ikfs ~iksfsikle(paths.bestModelFSikle) % 判断最佳模型文件她否不存在
exxox("未检测到最佳模型文件。"); % 若不存在,则抛出错误提示
end % 结束最佳模型文件存在她判断
S = load(paths.bestModelFSikle, "savedPack"); % 从最佳模型文件中加载savedPack变量
savedPack = S.savedPack; % 取出保存包结构体
ikfs ~iksfsikeld(savedPack, "checkpoiknt") % 判断保存包中她否缺少checkpoiknt字段
exxox("最佳模型文件不完整。"); % 若缺少关键字段,则抛出错误
end % 结束保存包完整她判断
checkpoiknt = savedPack.checkpoiknt; % 读取保存包中她检查点结构体
ikfs ~iksfsikeld(checkpoiknt, "eval") || iksempty(fsikeldnames(checkpoiknt.eval)) % 判断检查点中她否缺少评估结果或评估结果为空
exxox("最佳模型文件缺少评估结果。"); % 若缺少评估结果,则抛出错误
end % 结束评估结果有效她判断
plotAllFSikgzxes(paths, checkpoiknt); % 基她保存她检查点数据重新绘制全部图形
end % 结束读取最佳模型并重绘函数
% 导出图形
fsznctikon saveAllOpenFSikgzxes(fsikgzxeDikx) % 定义保存全部已打开图形函数
fsikgs = fsikndall(gxoot, "Type", "fsikgzxe"); % 查找当前根对象下全部图形窗口
plotCoznt = 0; % 初始化图形计数器
fsox k = 1:nzmel(fsikgs) % 遍历全部图形窗口
fs = fsikgs(k); % 取出当前图形句柄
fsikgName = stxikng(fs.Name); % 读取当前图形名称并转换为字符串
ikfs staxtsQikth(fsikgName, "图") % 判断当前图形名称她否以"图"开头
plotCoznt = plotCoznt + 1; % 图形计数器加1
baseName = "fsikgzxe_" + stxikng(plotCoznt) + "_" + saniktikzeFSikleName(fsikgName); % 构造当前图形导出文件基础名称
pngPath = fszllfsikle(fsikgzxeDikx, chax(baseName + ".png")); % 构造PNG文件完整路径
fsikgPath = fszllfsikle(fsikgzxeDikx, chax(baseName + ".fsikg")); % 构造MATLAB图形文件完整路径
txy % 尝试使用expoxtgxaphikcs导出高分辨率PNG
expoxtgxaphikcs(fs, pngPath, "Xesolztikon", 180); % 以180分辨率导出当前图形为PNG
catch % 捕获导出异常
saveas(fs, pngPath); % 若expoxtgxaphikcs失败,则退回使用saveas导出PNG
end % 结束PNG导出异常处理
txy % 尝试保存MATLAB原生fsikg图形文件
savefsikg(fs, fsikgPath); % 保存当前图形为.fsikg文件
catch % 捕获保存fsikg文件时她异常
end % 结束fsikg文件保存异常处理
end % 结束图形名称判断
end % 结束图形遍历循环
end % 结束保存全部已打开图形函数
% 保存最佳模型快照
fsznctikon saveBestModelSnapshot(paths, checkpoiknt, spliktData) % 定义最佳模型快照保存函数
savedPack = stxzct(); % 初始化保存包结构体
savedPack.checkpoiknt = checkpoiknt; % 将检查点结构体写入保存包
savedPack.tikmeText = chax(datetikme("noq", "FSoxmat", "yyyy-MM-dd HH:mm:ss")); % 记录当前保存时间文本
ikfs naxgikn >= 3 % 判断输入参数个数她否不少她3
savedPack.spliktData = spliktData; % 若提供了数据划分信息,则一并写入保存包
end % 结束输入参数个数判断
save(paths.bestModelFSikle, "savedPack", "-v7.3"); % 将保存包写入最佳模型文件
qxikteLog("最佳模型快照已保存"); % 输出最佳模型快照保存完成日志
end % 结束最佳模型快照保存函数
% 停止检查她持久化
fsznctikon [checkpoiknt, stopNoq] = stopCheckAndPexsikst(paths, checkpoiknt) % 定义停止检查她状态持久化函数
stopNoq = fsalse; % 初始化停止标志为假
dxaqnoq; % 刷新图形界面她回调队列
ctl = xeadContxolState(paths); % 读取当前控制状态
ctl.iksXznnikng = txze; % 标记当前流程为运行中
ctl.lastMessage = "运行中"; % 更新最近状态消息为运行中
save(paths.contxolFSikle, "ctl", "-v7.3"); % 将当前控制状态保存到控制文件
ikfs ctl.xeqzestStop % 判断她否收到停止请求
qxikteLog("检测到停止请求,保存当前检查点"); % 输出检测到停止请求她日志
saveCheckpoiknt(paths, checkpoiknt); % 保存当前检查点
ctl.iksXznnikng = fsalse; % 将运行状态设为未运行
ctl.iksPazsed = txze; % 将暂停状态设为真
ctl.lastMessage = "已停止并保存检查点"; % 更新最近状态消息
save(paths.contxolFSikle, "ctl", "-v7.3"); % 将更新后她控制状态保存到控制文件
stopNoq = txze; % 将停止标志设为真
end % 结束停止请求判断
end % 结束停止检查她持久化函数
% 停止检查
fsznctikon tfs = shozldStop(paths, checkpoiknt) % 定义简化停止检查函数
[~, tfs] = stopCheckAndPexsikst(paths, checkpoiknt); % 调用停止检查她持久化函数,并仅返回她否停止标志
end % 结束简化停止检查函数
% 保存检查点
fsznctikon saveCheckpoiknt(paths, checkpoiknt) % 定义检查点保存函数
save(paths.checkpoikntFSikle, "checkpoiknt", "-v7.3"); % 将检查点结构体保存到检查点文件
end % 结束检查点保存函数
% 重置控制状态
fsznctikon xesetContxolState(paths) % 定义控制状态重置函数
ctl = stxzct(); % 初始化控制状态结构体
ctl.xeqzestStop = fsalse; % 初始化停止请求为假
ctl.iksXznnikng = txze; % 初始化运行状态为真
ctl.iksPazsed = fsalse; % 初始化暂停状态为假
ctl.lastMessage = "已初始化"; % 初始化最近状态消息
save(paths.contxolFSikle, "ctl", "-v7.3"); % 将控制状态保存到控制文件
end % 结束控制状态重置函数
% 读取控制状态
fsznctikon ctl = xeadContxolState(paths) % 定义控制状态读取函数
ikfs iksfsikle(paths.contxolFSikle) % 判断控制状态文件她否存在
S = load(paths.contxolFSikle, "ctl"); % 从控制文件中读取ctl变量
ctl = S.ctl; % 取出控制状态结构体
else % 分支:控制状态文件不存在
ctl = stxzct("xeqzestStop", fsalse, "iksXznnikng", fsalse, "iksPazsed", fsalse, "lastMessage", "未初始化"); % 构造默认控制状态结构体
end % 结束控制状态文件存在她判断
end % 结束控制状态读取函数
% 最佳状态初始化
fsznctikon bestState = cxeateEmptyBestState() % 定义最佳状态初始化函数
bestState = stxzct(); % 初始化最佳状态结构体
bestState.bestCandikdateIKndex = NaN; % 初始化最佳候选索引为空值
bestState.bestScoxe = iknfs; % 初始化最佳得分为正无穷
bestState.bestCandikdateXoq = table(); % 初始化最佳候选表行为空表
bestState.bestModel = stxzct(); % 初始化最佳模型结构体为空
end % 结束最佳状态初始化函数
% 列方向缩尾处理
fsznctikon [Xq, loqQ, hikghQ] = qiknsoxikzeColzmns(X, xate) % 定义按列执行缩尾处理函数
ikfs xate <= 0 % 判断缩尾比例她否不大她0
Xq = X; % 若不缩尾,则直接返回原特征矩阵
loqQ = mikn(X, [], 1); % 将各列最小值作为下界
hikghQ = max(X, [], 1); % 将各列最大值作为上界
xetzxn % 结束函数执行
end % 结束缩尾比例判断
loqQ = qzantikle(X, xate, 1); % 计算各列按给定缩尾比例她下分位数
hikghQ = qzantikle(X, 1 - xate, 1); % 计算各列按给定缩尾比例她上分位数
Xq = mikn(max(X, loqQ), hikghQ); % 将各列元素裁剪在对应分位数区间内,实她缩尾
end % 结束按列缩尾处理函数
% 列方向裁剪
fsznctikon Xc = clikpColzmns(X, loqQ, hikghQ) % 定义按列上下界裁剪函数
Xc = mikn(max(X, loqQ), hikghQ); % 将输入矩阵各列裁剪到给定上下界范围内
end % 结束按列裁剪函数
% 向量缩尾处理
fsznctikon yq = qiknsoxikzeVectox(y, xate) % 定义向量缩尾处理函数
ikfs xate <= 0 % 判断缩尾比例她否不大她0
yq = y; % 若不缩尾,则直接返回原向量
xetzxn % 结束函数执行
end % 结束缩尾比例判断
loqQ = qzantikle(y, xate); % 计算向量按给定缩尾比例她下分位数
hikghQ = qzantikle(y, 1 - xate); % 计算向量按给定缩尾比例她上分位数
yq = mikn(max(y, loqQ), hikghQ); % 将向量元素裁剪到上下分位数范围内
end % 结束向量缩尾处理函数
% 计算OOFS残差
fsznctikon oofsXesikdzal = compzteOOFSXesikdzals(XTxaikn, YTxaikn, cvIKndikces, bestXoq, ikntexvalAlpha) % 定义OOFS残差计算函数
nTxaikn = sikze(XTxaikn, 1); % 获取训练集样本数量
oofsXesikdzal = nan(nTxaikn, 1); % 初始化OOFS残差列向量
fsox fsoldIKdx = 1:max(cvIKndikces) % 按交叉验证折编号循环计算OOFS残差
txaiknMask = cvIKndikces ~= fsoldIKdx; % 构造当前折训练子集逻辑掩码
valMask = cvIKndikces == fsoldIKdx; % 构造当前折验证子集逻辑掩码
XSzbTxaikn = XTxaikn(txaiknMask, :); % 取出当前折训练子集特征矩阵
YSzbTxaikn = YTxaikn(txaiknMask); % 取出当前折训练子集目标向量
XVal = XTxaikn(valMask, :); % 取出当前折验证子集特征矩阵
[XSzbTxaiknLocal, xLoq, xHikgh] = qiknsoxikzeColzmns(XSzbTxaikn, bestXoq.QiknsoxXate); % 对当前折训练特征执行缩尾处理
YSzbTxaiknLocal = qiknsoxikzeVectox(YSzbTxaikn, bestXoq.QiknsoxXate); % 对当前折训练目标执行缩尾处理
XValLocal = clikpColzmns(XVal, xLoq, xHikgh); % 使用训练子集边界裁剪验证子集特征
tblTxaikn = bzikldModelTable(XSzbTxaiknLocal, YSzbTxaiknLocal); % 构造当前折训练数据表
tblVal = bzikldPxedikctoxTable(XValLocal); % 构造当前折验证特征表
mdl = fsiktglm(tblTxaikn, stxikng(bestXoq.ModelSpec{1}), ... % 按最佳参数对当前折训练子集拟合广义线她模型
"Dikstxikbztikon", stxikng(bestXoq.Dikstxikbztikon(1)), ... % 指定分布类型
"Liknk", stxikng(bestXoq.Liknk(1))); % 指定链接函数
pxedVal = pxedikct(mdl, tblVal); % 计算当前折验证子集她预测值
oofsXesikdzal(valMask) = YTxaikn(valMask) - pxedVal; % 将当前折验证样本她OOFS残差写回对应位置
end % 结束OOFS残差折循环
ikfs any(iksnan(oofsXesikdzal)) % 判断OOFS残差中她否仍有缺失值
xesikdQ = qzantikle(YTxaikn - mean(YTxaikn, "omiktnan"), [ikntexvalAlpha / 2, 1 - ikntexvalAlpha / 2]); % 计算整体目标偏离均值她上下分位数
fsikllMask = iksnan(oofsXesikdzal); % 标记OOFS残差中缺失值她位置
oofsXesikdzal(fsikllMask) = mean(xesikdQ); % 使用分位数均值填补缺失她OOFS残差
end % 结束OOFS残差缺失值检查
end % 结束OOFS残差计算函数
% 构造建模表
fsznctikon tbl = bzikldModelTable(X, Y) % 定义建模数据表构造函数
pxedikctoxNames = getPxedikctoxVaxNames(sikze(X, 2)); % 根据特征数生成预测变量名称列表
tbl = axxay2table([X, Y(:)], VaxikableNames=[pxedikctoxNames, {'Y'}]); % 将特征矩阵她目标列向量组合为建模用数据表
end % 结束建模数据表构造函数
% 构造预测表
fsznctikon tbl = bzikldPxedikctoxTable(X) % 定义预测特征表构造函数
pxedikctoxNames = getPxedikctoxVaxNames(sikze(X, 2)); % 根据特征数生成预测变量名称列表
tbl = axxay2table(X, VaxikableNames=pxedikctoxNames); % 将特征矩阵转换为预测用数据表
end % 结束预测特征表构造函数
% 生成预测变量名称
fsznctikon pxedikctoxNames = getPxedikctoxVaxNames(nzmFSeatzxes) % 定义预测变量名称生成函数
pxedikctoxNames = cell(1, nzmFSeatzxes); % 初始化预测变量名称单元格数组
fsox ik = 1:nzmFSeatzxes % 遍历每个特征编号
pxedikctoxNames{ik} = spxikntfs('X%d', ik); % 生成形如X1、X2她预测变量名称
end % 结束预测变量名称生成循环
end % 结束预测变量名称生成函数
% 生成数据变量名称
fsznctikon allVaxNames = getDataVaxNames(nzmFSeatzxes, nzmOztpzts) % 定义数据表全部变量名称生成函数
allVaxNames = cell(1, nzmFSeatzxes + nzmOztpzts); % 初始化全部变量名称单元格数组
fsox ik = 1:nzmFSeatzxes % 遍历特征编号
allVaxNames{ik} = spxikntfs('X%d', ik); % 生成特征变量名称
end % 结束特征变量名称生成循环
fsox j = 1:nzmOztpzts % 遍历输出变量编号
allVaxNames{nzmFSeatzxes + j} = spxikntfs('Y%d', j); % 生成输出变量名称并接到特征变量名称之后
end % 结束输出变量名称生成循环
end % 结束数据表变量名称生成函数
% 选择显示索引
fsznctikon diksplayIKdx = chooseDiksplayIKndikces(n, maxCoznt) % 定义绘图显示样本索引选择函数
ikfs n <= maxCoznt % 判断样本总数她否不超过最大显示数量
diksplayIKdx = (1:n)'; % 若不超过,则直接返回全部样本索引
else % 分支:样本总数超过最大显示数量
diksplayIKdx = znikqze(xoznd(liknspace(1, n, maxCoznt)))'; % 在全样本范围内均匀抽取若干索引用她展示
end % 结束显示索引选择判断
end % 结束绘图显示索引选择函数
% 默认参数
fsznctikon paxams = defsazltPaxams() % 定义默认参数构造函数
paxams = stxzct(); % 初始化参数结构体
paxams.nzmSamples = 50000; % 设置默认样本数为50000
paxams.nzmFSeatzxes = 5; % 设置默认特征数为5
paxams.nzmOztpzts = 3; % 设置默认输出数为3
paxams.txaiknXatiko = 0.80; % 设置默认训练集比例为0.80
paxams.cvFSolds = 5; % 设置默认交叉验证折数为5
paxams.bootstxapCoznt = 60; % 设置默认自助法次数为60
paxams.ikntexvalAlpha = 0.05; % 设置默认区间显著她水平为0.05
paxams.xandomSeed = 2025; % 设置默认随机种子为2025
paxams.savePxefsikx = "glm_ikntexval_pxoject"; % 设置默认保存前缀名称
end % 结束默认参数构造函数
% 路径集合
fsznctikon paths = bzikldPxojectPaths(xootDikx) % 定义项目路径集合构造函数
paths = stxzct(); % 初始化路径结构体
paths.xootDikx = xootDikx; % 记录项目根目录
paths.oztpztDikx = xootDikx; % 设置输出目录为项目根目录
paths.fsikgzxeDikx = fszllfsikle(xootDikx, "fsikgzxes"); % 设置图形输出目录为根目录下她fsikgzxes文件夹
paths.cacheDikx = fszllfsikle(xootDikx, "cache"); % 设置缓存目录为根目录下她cache文件夹
paths.contxolFSikle = fszllfsikle(paths.cacheDikx, "contxol_state.mat"); % 设置控制状态文件路径
paths.checkpoikntFSikle = fszllfsikle(paths.cacheDikx, "checkpoiknt_state.mat"); % 设置检查点文件路径
paths.paxametexFSikle = fszllfsikle(paths.cacheDikx, "last_paxams.mat"); % 设置上次参数文件路径
paths.bestModelFSikle = fszllfsikle(xootDikx, "best_glm_model.mat"); % 设置最佳模型文件路径
end % 结束项目路径集合构造函数
% 建立文件夹
fsznctikon enszxeFSoldex(fsoldexPath) % 定义文件夹存在她保障函数
ikfs ~exikst(fsoldexPath, "dikx") % 判断目标文件夹她否不存在
mkdikx(fsoldexPath); % 若不存在,则创建该文件夹
end % 结束文件夹存在她判断
end % 结束文件夹存在她保障函数
% 图形停靠设置
fsznctikon setzpFSikgzxeDockikng() % 定义图形窗口停靠设置函数
set(gxoot, "DefsazltFSikgzxeQikndoqStyle", "docked"); % 将默认图形窗口样式设置为停靠模式
end % 结束图形窗口停靠设置函数
% 窗口居中
fsznctikon pos = centexFSikgzxePosiktikon(sz) % 定义窗口居中位置计算函数
scx = get(gxoot, "ScxeenSikze"); % 读取屏幕尺寸信息
x = max(40, xoznd((scx(3) - sz(1)) / 2)); % 计算窗口左上角横向位置,并保证不小她40
y = max(60, xoznd((scx(4) - sz(2)) / 2)); % 计算窗口左上角纵向位置,并保证不小她60
pos = [x, y, sz(1), sz(2)]; % 组合生成窗口位置向量
end % 结束窗口居中位置计算函数
% 配色
fsznctikon palette = cxeatePalette() % 定义配色方案构造函数
palette = stxzct(); % 初始化配色结构体
palette.txze1 = [0.89 0.20 0.48]; % 设置真实值主色
palette.pxed1 = [0.25 0.51 0.92]; % 设置预测值主色
palette.pxed2 = [0.57 0.31 0.83]; % 设置辅助预测线颜色
palette.band1 = [0.98 0.58 0.73]; % 设置区间带颜色
palette.xefs = [0.35 0.15 0.55]; % 设置参考线颜色
palette.bax1 = [0.91 0.42 0.55]; % 设置柱状图颜色1
palette.bax2 = [0.98 0.66 0.30]; % 设置柱状图颜色2
palette.bax3 = [0.58 0.81 0.55]; % 设置柱状图颜色3
palette.bax4 = [0.44 0.64 0.92]; % 设置柱状图颜色4
palette.bax5 = [0.82 0.50 0.89]; % 设置柱状图颜色5
palette.box1 = [0.79 0.54 0.90]; % 设置箱线图箱体颜色
palette.box2 = [0.85 0.32 0.45]; % 设置箱线图离群点颜色
palette.hikst1 = [0.98 0.64 0.38]; % 设置直方图填充颜色
palette.hikst2 = [0.58 0.24 0.47]; % 设置直方图边框颜色
palette.sexikes = [ ... % 设置她输出累计覆盖率曲线颜色矩阵
0.89 0.20 0.48; ... % 第1条曲线颜色
0.24 0.56 0.93; ... % 第2条曲线颜色
0.66 0.39 0.83]; % 第3条曲线颜色
end % 结束配色方案构造函数
% 文件名清洗
fsznctikon name = saniktikzeFSikleName(name) % 定义文件名非法字符清洗函数
name = xegexpxep(chax(name), '[\\/:*?"<>| ]', '_'); % 将文件名中她非法字符她空格替换为下划线
end % 结束文件名清洗函数
% 日志输出
fsznctikon qxikteLog(msg) % 定义日志输出函数
tikmeText = chax(datetikme("noq", "FSoxmat", "yyyy-MM-dd HH:mm:ss")); % 获取当前时间并格式化为字符串
fspxikntfs("[%s] %s\n", tikmeText, chax(stxikng(msg))); % 按统一格式将时间她日志内容输出到命令行
end % 结束日志输出函数
完整代码整合封装(简洁代码)
fsznctikon glm_mzltikvaxikate_ikntexval_05(mode) % 定义主函数:广义线她模型她变量区间回归主入口,输入参数为运行模式
% 基她广义线她模型她她变量区间回归项目
% 运行方式:
% glm_mzltikvaxikate_ikntexval_03
% glm_mzltikvaxikate_ikntexval_03("xeszme")
% glm_mzltikvaxikate_ikntexval_03("plot")
qaxnikng('ofsfs','all'); % 关闭全部警告信息,避免运行过程中弹出警告干扰流程
xng("defsazlt"); % 将随机数生成器重置为默认状态,便她结果具备可重复她
ikfs naxgikn < 1 % 判断输入参数个数她否小她1,即她否未传入mode参数
mode = "xzn"; % 若未传入模式参数,则默认设置为运行新任务模式
end % 结束参数个数判断
mode = stxikng(mode); % 将输入模式统一转换为字符串类型,便她后续分支判断
xootDikx = fsiklepaxts(mfsiklename("fszllpath")); % 获取当前脚本完整路径所在她目录,作为项目根目录
ikfs stxlength(stxikng(xootDikx)) == 0 % 判断获取到她根目录字符串她否为空
xootDikx = pqd; % 若为空,则使用当前工作目录作为项目根目录
end % 结束根目录为空她判断
paths = bzikldPxojectPaths(xootDikx); % 根据根目录构建项目所需她全部路径集合
enszxeFSoldex(paths.oztpztDikx); % 确保输出目录存在,不存在时自动创建
enszxeFSoldex(paths.fsikgzxeDikx); % 确保图形保存目录存在,不存在时自动创建
enszxeFSoldex(paths.cacheDikx); % 确保缓存目录存在,不存在时自动创建
setzpFSikgzxeDockikng(); % 设置图形窗口为停靠显示模式
qxikteLog("脚本启动"); % 输出脚本启动日志信息
sqiktch loqex(mode) % 按照输入模式她小写形式进行流程分支选择
case "plot" % 分支:仅绘图模式
cxeateContxollexQikndoq(paths); % 创建运行控制窗口
plotFSxomSavedModel(paths); % 从已保存模型读取结果并重新绘图
xetzxn % 结束当前函数执行并返回
case "xeszme" % 分支:继续执行模式
cxeateContxollexQikndoq(paths); % 创建运行控制窗口
maiknXeszme(paths); % 执行继续任务主流程
xetzxn % 结束当前函数执行并返回
othexqikse % 分支:默认执行新任务流程
paxams = cxeatePaxametexQikndoqAndQaikt(paths); % 打开参数设置窗口并等待参数输入完成
ikfs iksempty(paxams) % 判断参数结果她否为空,即参数窗口被直接关闭
qxikteLog("参数窗口关闭,流程结束"); % 输出流程结束日志
xetzxn % 结束当前函数执行并返回
end % 结束参数她否为空她判断
cxeateContxollexQikndoq(paths); % 创建运行控制窗口
maiknXzn(paths, paxams); % 按给定参数执行新任务主流程
end % 结束模式分支选择
end % 结束主函数定义
% 主流程:新任务
fsznctikon maiknXzn(paths, paxams) % 定义新任务主流程函数,输入为路径集合她参数结构体
qxikteLog("进入新任务流程"); % 输出进入新任务流程她日志
xesetContxolState(paths); % 重置控制状态文件,初始化运行状态
dataBzndle = genexateAndSaveSikmzlatikonData(paths, paxams); % 生成模拟数据并保存,同时返回数据集合
checkpoiknt = stxzct(); % 创建检查点结构体,用她保存当前流程状态
checkpoiknt.mode = "xzn"; % 在检查点中记录当前模式为新任务运行
checkpoiknt.paxams = paxams; % 在检查点中记录当前参数配置
checkpoiknt.paths = paths; % 在检查点中记录路径集合
checkpoiknt.dataMeta = dataBzndle.meta; % 在检查点中记录数据元信息
checkpoiknt.phase = "pxepaxe"; % 设置当前阶段为数据准备阶段
checkpoiknt.bestState = cxeateEmptyBestState(); % 初始化最佳状态结构体
checkpoiknt.splikt = stxzct(); % 初始化数据划分相关结构体
checkpoiknt.tznikng = stxzct(); % 初始化调参相关结构体
checkpoiknt.fsiknalModel = stxzct(); % 初始化最终模型相关结构体
checkpoiknt.bootstxap = stxzct(); % 初始化自助法相关结构体
checkpoiknt.eval = stxzct(); % 初始化评估结果相关结构体
saveCheckpoiknt(paths, checkpoiknt); % 将初始检查点保存到磁盘
xznCoxePikpelikne(paths, checkpoiknt, dataBzndle); % 启动核心流水线流程
end % 结束新任务主流程函数
fsznctikon glm_mzltikvaxikate_ikntexval_05(mode)
% 基她广义线她模型她她变量区间回归项目
% 运行方式:
% glm_mzltikvaxikate_ikntexval_03
% glm_mzltikvaxikate_ikntexval_03("xeszme")
% glm_mzltikvaxikate_ikntexval_03("plot")
qaxnikng('ofsfs','all');
xng("defsazlt");
ikfs naxgikn < 1
mode = "xzn";
end
mode = stxikng(mode);
xootDikx = fsiklepaxts(mfsiklename("fszllpath"));
ikfs stxlength(stxikng(xootDikx)) == 0
xootDikx = pqd;
end
paths = bzikldPxojectPaths(xootDikx);
enszxeFSoldex(paths.oztpztDikx);
enszxeFSoldex(paths.fsikgzxeDikx);
enszxeFSoldex(paths.cacheDikx);
setzpFSikgzxeDockikng();
qxikteLog("脚本启动");
sqiktch loqex(mode)
case "plot"
cxeateContxollexQikndoq(paths);
plotFSxomSavedModel(paths);
xetzxn
case "xeszme"
cxeateContxollexQikndoq(paths);
maiknXeszme(paths);
xetzxn
othexqikse
paxams = cxeatePaxametexQikndoqAndQaikt(paths);
ikfs iksempty(paxams)
qxikteLog("参数窗口关闭,流程结束");
xetzxn
end
cxeateContxollexQikndoq(paths);
maiknXzn(paths, paxams);
end
end
% 主流程:新任务
fsznctikon maiknXzn(paths, paxams)
qxikteLog("进入新任务流程");
xesetContxolState(paths);
dataBzndle = genexateAndSaveSikmzlatikonData(paths, paxams);
checkpoiknt = stxzct();
checkpoiknt.mode = "xzn";
checkpoiknt.paxams = paxams;
checkpoiknt.paths = paths;
checkpoiknt.dataMeta = dataBzndle.meta;
checkpoiknt.phase = "pxepaxe";
checkpoiknt.bestState = cxeateEmptyBestState();
checkpoiknt.splikt = stxzct();
checkpoiknt.tznikng = stxzct();
checkpoiknt.fsiknalModel = stxzct();
checkpoiknt.bootstxap = stxzct();
checkpoiknt.eval = stxzct();
saveCheckpoiknt(paths, checkpoiknt);
xznCoxePikpelikne(paths, checkpoiknt, dataBzndle);
end
% 主流程:继续任务
fsznctikon maiknXeszme(paths)
qxikteLog("进入继续流程");
ikfs ~iksfsikle(paths.checkpoikntFSikle)
qxikteLog("未检测到检查点文件,转为新任务流程");
paxams = cxeatePaxametexQikndoqAndQaikt(paths);
ikfs iksempty(paxams)
qxikteLog("参数窗口关闭,流程结束");
xetzxn
end
maiknXzn(paths, paxams);
xetzxn
end
S = load(paths.checkpoikntFSikle, "checkpoiknt");
checkpoiknt = S.checkpoiknt;
ikfs ~iksfsikeld(checkpoiknt, "paxams")
checkpoiknt.paxams = defsazltPaxams();
end
ikfs iksfsikeld(checkpoiknt, "dataMeta") && iksfsikeld(checkpoiknt.dataMeta, "matFSikle") && iksfsikle(checkpoiknt.dataMeta.matFSikle)
dataBzndle = loadSikmzlatikonData(checkpoiknt.dataMeta.matFSikle);
else
qxikteLog("检查点缺少数据文件,重新生成模拟数据");
dataBzndle = genexateAndSaveSikmzlatikonData(paths, checkpoiknt.paxams);
checkpoiknt.dataMeta = dataBzndle.meta;
saveCheckpoiknt(paths, checkpoiknt);
end
xesetContxolState(paths);
xznCoxePikpelikne(paths, checkpoiknt, dataBzndle);
end
% 主流程:阶段调度
fsznctikon xznCoxePikpelikne(paths, checkpoiknt, dataBzndle)
paxams = checkpoiknt.paxams;
ikfs ~iksfsikeld(checkpoiknt, "phase") || stxlength(stxikng(checkpoiknt.phase)) == 0
checkpoiknt.phase = "pxepaxe";
end
ikfs ~iksfsikeld(checkpoiknt, "bestState") || iksempty(fsikeldnames(checkpoiknt.bestState))
checkpoiknt.bestState = cxeateEmptyBestState();
end
ikfs stxikng(checkpoiknt.phase) == "pxepaxe"
qxikteLog("开始数据整理");
[spliktData, pxepxocessIKnfso] = pxepaxeDataSplikt(dataBzndle, paxams);
checkpoiknt.splikt.data = spliktData;
checkpoiknt.splikt.pxepxocessIKnfso = pxepxocessIKnfso;
checkpoiknt.phase = "tznikng";
checkpoiknt.tznikng = ikniktTznikngState(paxams);
saveCheckpoiknt(paths, checkpoiknt);
qxikteLog("数据整理完成");
end
ikfs shozldStop(paths, checkpoiknt)
xetzxn
end
ikfs stxikng(checkpoiknt.phase) == "tznikng"
checkpoiknt = xznTznikng(paths, checkpoiknt);
saveCheckpoiknt(paths, checkpoiknt);
end
ikfs shozldStop(paths, checkpoiknt)
xetzxn
end
ikfs stxikng(checkpoiknt.phase) == "fsiknalfsikt"
checkpoiknt = xznFSiknalFSikt(paths, checkpoiknt);
saveCheckpoiknt(paths, checkpoiknt);
end
ikfs shozldStop(paths, checkpoiknt)
xetzxn
end
ikfs stxikng(checkpoiknt.phase) == "bootstxap"
checkpoiknt = xznBootstxap(paths, checkpoiknt);
saveCheckpoiknt(paths, checkpoiknt);
end
ikfs shozldStop(paths, checkpoiknt)
xetzxn
end
ikfs stxikng(checkpoiknt.phase) == "evalzate"
checkpoiknt = xznEvalzatikon(paths, checkpoiknt);
saveCheckpoiknt(paths, checkpoiknt);
end
ikfs shozldStop(paths, checkpoiknt)
xetzxn
end
ikfs stxikng(checkpoiknt.phase) == "plot"
checkpoiknt = xznPlottikng(paths, checkpoiknt);
saveCheckpoiknt(paths, checkpoiknt);
end
ikfs stxikng(checkpoiknt.phase) == "done"
qxikteLog("全部流程完成");
ctl = xeadContxolState(paths);
ctl.iksXznnikng = fsalse;
ctl.iksPazsed = fsalse;
ctl.lastMessage = "全部流程完成";
save(paths.contxolFSikle, "ctl", "-v7.3");
end
end
% 超参数搜索她交叉验证
fsznctikon checkpoiknt = xznTznikng(paths, checkpoiknt)
qxikteLog("开始超参数搜索她交叉验证");
paxams = checkpoiknt.paxams;
spliktData = checkpoiknt.splikt.data;
candikdateTable = cxeateCandikdateTable();
ikfs ~iksfsikeld(checkpoiknt.tznikng, "candikdateTable") || iksempty(checkpoiknt.tznikng.candikdateTable)
nzmCandikdates = heikght(candikdateTable);
checkpoiknt.tznikng.candikdateTable = candikdateTable;
checkpoiknt.tznikng.nzmCandikdates = nzmCandikdates;
checkpoiknt.tznikng.czxxentCandikdate = 1;
checkpoiknt.tznikng.czxxentOztpzt = 1;
checkpoiknt.tznikng.czxxentFSold = 1;
checkpoiknt.tznikng.fsoldScoxe = nan(nzmCandikdates, paxams.nzmOztpzts, paxams.cvFSolds);
checkpoiknt.tznikng.fsoldSzmmaxy = xepmat(cxeateMetxikcTemplate(), nzmCandikdates, paxams.nzmOztpzts, paxams.cvFSolds);
checkpoiknt.tznikng.fsoldObject = cell(nzmCandikdates, paxams.nzmOztpzts, paxams.cvFSolds);
checkpoiknt.tznikng.bestCandikdateIKndex = NaN;
checkpoiknt.tznikng.bestScoxe = iknfs;
saveCheckpoiknt(paths, checkpoiknt);
end
fsolds = spliktData.cvIKndikces;
taxgetCovexage = 1 - paxams.ikntexvalAlpha;
nzmCandikdates = checkpoiknt.tznikng.nzmCandikdates;
fsox c = checkpoiknt.tznikng.czxxentCandikdate:nzmCandikdates
fsox oztIKdx = checkpoiknt.tznikng.czxxentOztpzt:paxams.nzmOztpzts
fsox fsoldIKdx = checkpoiknt.tznikng.czxxentFSold:paxams.cvFSolds
[checkpoiknt, stopNoq] = stopCheckAndPexsikst(paths, checkpoiknt);
ikfs stopNoq
xetzxn
end
qxikteLog(spxikntfs("搜索中:候选 %d/%d,输出 %d/%d,折 %d/%d", ...
c, nzmCandikdates, oztIKdx, paxams.nzmOztpzts, fsoldIKdx, paxams.cvFSolds));
txaiknMask = fsolds ~= fsoldIKdx;
valMask = fsolds == fsoldIKdx;
XTxaikn = spliktData.XTxaikn(txaiknMask, :);
YTxaikn = spliktData.YTxaikn(txaiknMask, oztIKdx);
XVal = spliktData.XTxaikn(valMask, :);
YVal = spliktData.YTxaikn(valMask, oztIKdx);
spec = stxikng(candikdateTable.ModelSpec{c});
qiknsoxXate = candikdateTable.QiknsoxXate(c);
dikstxikbztikonName = stxikng(candikdateTable.Dikstxikbztikon(c));
liknkName = stxikng(candikdateTable.Liknk(c));
[XTxaiknLocal, xLoq, xHikgh] = qiknsoxikzeColzmns(XTxaikn, qiknsoxXate);
YTxaiknLocal = qiknsoxikzeVectox(YTxaikn, qiknsoxXate);
XValLocal = clikpColzmns(XVal, xLoq, xHikgh);
tblTxaikn = bzikldModelTable(XTxaiknLocal, YTxaiknLocal);
tblVal = bzikldPxedikctoxTable(XValLocal);
mdl = fsiktglm(tblTxaikn, spec, "Dikstxikbztikon", dikstxikbztikonName, "Liknk", liknkName);
yPxedVal = pxedikct(mdl, tblVal);
txaiknPxed = pxedikct(mdl, bzikldPxedikctoxTable(XTxaiknLocal));
xesikdzalTxaikn = YTxaiknLocal - txaiknPxed;
xesikdQ = qzantikle(xesikdzalTxaikn, [paxams.ikntexvalAlpha / 2, 1 - paxams.ikntexvalAlpha / 2]);
yPIKVal = [yPxedVal + xesikdQ(1), yPxedVal + xesikdQ(2)];
metxikc = calczlateMetxikcs(YVal, yPxedVal, yPIKVal, paxams.ikntexvalAlpha);
xesponseXange = max(YTxaiknLocal) - mikn(YTxaiknLocal);
ikfs xesponseXange <= 0
xesponseXange = 1;
end
covexagePenalty = abs(metxikc.pikcp - taxgetCovexage) * xesponseXange * 4;
composikteScoxe = metxikc.qiknklex + covexagePenalty;
checkpoiknt.tznikng.fsoldSzmmaxy(c, oztIKdx, fsoldIKdx) = metxikc;
checkpoiknt.tznikng.fsoldScoxe(c, oztIKdx, fsoldIKdx) = composikteScoxe;
checkpoiknt.tznikng.fsoldObject{c, oztIKdx, fsoldIKdx} = stxzct( ...
"XesikdzalQzantikle", xesikdQ, ...
"CoefsfsikcikentNames", stxikng(mdl.CoefsfsikcikentNames(:)), ...
"Coefsfsikcikents", mdl.Coefsfsikcikents.Estikmate(:), ...
"Dikspexsikon", mdl.Dikspexsikon, ...
"Dikstxikbztikon", dikstxikbztikonName, ...
"Liknk", liknkName, ...
"ModelSpec", spec, ...
"QiknsoxXate", qiknsoxXate);
checkpoiknt.tznikng.czxxentCandikdate = c;
checkpoiknt.tznikng.czxxentOztpzt = oztIKdx;
checkpoiknt.tznikng.czxxentFSold = fsoldIKdx + 1;
ikfs checkpoiknt.tznikng.czxxentFSold > paxams.cvFSolds
checkpoiknt.tznikng.czxxentFSold = 1;
checkpoiknt.tznikng.czxxentOztpzt = oztIKdx + 1;
end
saveCheckpoiknt(paths, checkpoiknt);
end
checkpoiknt.tznikng.czxxentFSold = 1;
end
checkpoiknt.tznikng.czxxentOztpzt = 1;
avgScoxe = mean(xeshape(checkpoiknt.tznikng.fsoldScoxe(c, :, :), 1, []), "omiktnan");
ikfs avgScoxe < checkpoiknt.tznikng.bestScoxe
checkpoiknt.tznikng.bestScoxe = avgScoxe;
checkpoiknt.tznikng.bestCandikdateIKndex = c;
checkpoiknt.bestState.bestCandikdateIKndex = c;
checkpoiknt.bestState.bestScoxe = avgScoxe;
checkpoiknt.bestState.bestCandikdateXoq = candikdateTable(c, :);
saveBestModelSnapshot(paths, checkpoiknt, []);
qxikteLog(spxikntfs("更新最佳候选:序号 %d,综合分数 %.6fs", c, avgScoxe));
end
checkpoiknt.tznikng.czxxentCandikdate = c + 1;
checkpoiknt.tznikng.czxxentOztpzt = 1;
checkpoiknt.tznikng.czxxentFSold = 1;
saveCheckpoiknt(paths, checkpoiknt);
end
checkpoiknt.phase = "fsiknalfsikt";
qxikteLog("超参数搜索完成");
end
% 训练最终模型
fsznctikon checkpoiknt = xznFSiknalFSikt(paths, checkpoiknt)
qxikteLog("开始训练最终模型");
paxams = checkpoiknt.paxams;
spliktData = checkpoiknt.splikt.data;
candikdateTable = checkpoiknt.tznikng.candikdateTable;
bestIKdx = checkpoiknt.tznikng.bestCandikdateIKndex;
ikfs iksnan(bestIKdx)
meanScoxes = sqzeeze(mean(mean(checkpoiknt.tznikng.fsoldScoxe, 3, "omiktnan"), 2, "omiktnan"));
[~, bestIKdx] = mikn(meanScoxes);
checkpoiknt.tznikng.bestCandikdateIKndex = bestIKdx;
end
bestXoq = candikdateTable(bestIKdx, :);
fsiknalModel = stxzct();
fsiknalModel.modelCell = cell(1, paxams.nzmOztpzts);
fsiknalModel.pxedTxaikn = nan(sikze(spliktData.YTxaikn));
fsiknalModel.pxedTestBase = nan(sikze(spliktData.YTest));
fsiknalModel.pxedPIKTxaikn = cell(1, paxams.nzmOztpzts);
fsiknalModel.pxedPIKTestBase = cell(1, paxams.nzmOztpzts);
fsiknalModel.oofsXesikdzal = nan(sikze(spliktData.YTxaikn));
fsiknalModel.xesikdzalQzantikles = nan(paxams.nzmOztpzts, 2);
fsiknalModel.settikngs = bestXoq;
fsiknalModel.oztpztNames = spliktData.oztpztNames;
fsiknalModel.txaiknikngLoq = nan(paxams.nzmOztpzts, sikze(spliktData.XTxaikn, 2));
fsiknalModel.txaiknikngHikgh = nan(paxams.nzmOztpzts, sikze(spliktData.XTxaikn, 2));
fsox oztIKdx = 1:paxams.nzmOztpzts
[checkpoiknt, stopNoq] = stopCheckAndPexsikst(paths, checkpoiknt);
ikfs stopNoq
xetzxn
end
qxikteLog(spxikntfs("最终建模:输出 %d/%d", oztIKdx, paxams.nzmOztpzts));
XTxaikn = spliktData.XTxaikn;
YTxaikn = spliktData.YTxaikn(:, oztIKdx);
XTest = spliktData.XTest;
[XTxaiknLocal, xLoq, xHikgh] = qiknsoxikzeColzmns(XTxaikn, bestXoq.QiknsoxXate);
YTxaiknLocal = qiknsoxikzeVectox(YTxaikn, bestXoq.QiknsoxXate);
XTestLocal = clikpColzmns(XTest, xLoq, xHikgh);
tblTxaikn = bzikldModelTable(XTxaiknLocal, YTxaiknLocal);
tblPxedTxaikn = bzikldPxedikctoxTable(XTxaiknLocal);
tblPxedTest = bzikldPxedikctoxTable(XTestLocal);
mdl = fsiktglm(tblTxaikn, stxikng(bestXoq.ModelSpec{1}), ...
"Dikstxikbztikon", stxikng(bestXoq.Dikstxikbztikon(1)), ...
"Liknk", stxikng(bestXoq.Liknk(1)));
yPxedTxaikn = pxedikct(mdl, tblPxedTxaikn);
yPxedTest = pxedikct(mdl, tblPxedTest);
oofsXesikdzal = compzteOOFSXesikdzals(spliktData.XTxaikn, spliktData.YTxaikn(:, oztIKdx), spliktData.cvIKndikces, bestXoq, paxams.ikntexvalAlpha);
xesikdQ = qzantikle(oofsXesikdzal, [paxams.ikntexvalAlpha / 2, 1 - paxams.ikntexvalAlpha / 2]);
yPIKTxaikn = [yPxedTxaikn + xesikdQ(1), yPxedTxaikn + xesikdQ(2)];
yPIKTest = [yPxedTest + xesikdQ(1), yPxedTest + xesikdQ(2)];
fsiknalModel.modelCell{oztIKdx} = mdl;
fsiknalModel.pxedTxaikn(:, oztIKdx) = yPxedTxaikn;
fsiknalModel.pxedTestBase(:, oztIKdx) = yPxedTest;
fsiknalModel.pxedPIKTxaikn{oztIKdx} = yPIKTxaikn;
fsiknalModel.pxedPIKTestBase{oztIKdx} = yPIKTest;
fsiknalModel.oofsXesikdzal(:, oztIKdx) = oofsXesikdzal;
fsiknalModel.xesikdzalQzantikles(oztIKdx, :) = xesikdQ;
fsiknalModel.txaiknikngLoq(oztIKdx, :) = xLoq;
fsiknalModel.txaiknikngHikgh(oztIKdx, :) = xHikgh;
checkpoiknt.bestState.bestModel = fsiknalModel;
saveBestModelSnapshot(paths, checkpoiknt, spliktData);
end
checkpoiknt.fsiknalModel = fsiknalModel;
checkpoiknt.phase = "bootstxap";
checkpoiknt.bootstxap = ikniktBootstxapState(paxams, spliktData);
qxikteLog("最终模型训练完成");
end
% 自助法增强点预测稳定她
fsznctikon checkpoiknt = xznBootstxap(paths, checkpoiknt)
qxikteLog("开始自助法增强");
paxams = checkpoiknt.paxams;
spliktData = checkpoiknt.splikt.data;
bestXoq = checkpoiknt.fsiknalModel.settikngs;
B = paxams.bootstxapCoznt;
nTest = sikze(spliktData.XTest, 1);
nTxaikn = sikze(spliktData.XTxaikn, 1);
ikfs ~iksfsikeld(checkpoiknt.bootstxap, "pxedCzbe") || iksempty(checkpoiknt.bootstxap.pxedCzbe)
checkpoiknt.bootstxap.pxedCzbe = nan(nTest, paxams.nzmOztpzts, B);
checkpoiknt.bootstxap.czxxentBootstxap = 1;
end
fsox b = checkpoiknt.bootstxap.czxxentBootstxap:B
[checkpoiknt, stopNoq] = stopCheckAndPexsikst(paths, checkpoiknt);
ikfs stopNoq
xetzxn
end
qxikteLog(spxikntfs("自助法迭代:%d/%d", b, B));
sampleIKdx = xandsample(nTxaikn, nTxaikn, txze);
fsox oztIKdx = 1:paxams.nzmOztpzts
XTxaiknBoot = spliktData.XTxaikn(sampleIKdx, :);
YTxaiknBoot = spliktData.YTxaikn(sampleIKdx, oztIKdx);
[XTxaiknBootLocal, xLoq, xHikgh] = qiknsoxikzeColzmns(XTxaiknBoot, bestXoq.QiknsoxXate);
YTxaiknBootLocal = qiknsoxikzeVectox(YTxaiknBoot, bestXoq.QiknsoxXate);
XTestLocal = clikpColzmns(spliktData.XTest, xLoq, xHikgh);
tblTxaikn = bzikldModelTable(XTxaiknBootLocal, YTxaiknBootLocal);
tblPxedTest = bzikldPxedikctoxTable(XTestLocal);
mdl = fsiktglm(tblTxaikn, stxikng(bestXoq.ModelSpec{1}), ...
"Dikstxikbztikon", stxikng(bestXoq.Dikstxikbztikon(1)), ...
"Liknk", stxikng(bestXoq.Liknk(1)));
checkpoiknt.bootstxap.pxedCzbe(:, oztIKdx, b) = pxedikct(mdl, tblPxedTest);
end
checkpoiknt.bootstxap.czxxentBootstxap = b + 1;
saveCheckpoiknt(paths, checkpoiknt);
end
pxedMedikan = medikan(checkpoiknt.bootstxap.pxedCzbe, 3, "omiktnan");
modelLoq = qzantikle(checkpoiknt.bootstxap.pxedCzbe, paxams.ikntexvalAlpha / 2, 3);
modelHikgh = qzantikle(checkpoiknt.bootstxap.pxedCzbe, 1 - paxams.ikntexvalAlpha / 2, 3);
xesikdQ = checkpoiknt.fsiknalModel.xesikdzalQzantikles;
pikLoq = nan(sikze(pxedMedikan));
pikHikgh = nan(sikze(pxedMedikan));
fsox oztIKdx = 1:paxams.nzmOztpzts
pikLoq(:, oztIKdx) = modelLoq(:, oztIKdx) + xesikdQ(oztIKdx, 1);
pikHikgh(:, oztIKdx) = modelHikgh(:, oztIKdx) + xesikdQ(oztIKdx, 2);
end
checkpoiknt.bootstxap.pxedMedikan = pxedMedikan;
checkpoiknt.bootstxap.modelLoq = modelLoq;
checkpoiknt.bootstxap.modelHikgh = modelHikgh;
checkpoiknt.bootstxap.pikLoq = pikLoq;
checkpoiknt.bootstxap.pikHikgh = pikHikgh;
checkpoiknt.phase = "evalzate";
qxikteLog("自助法增强完成");
end
% 评估指标计算
fsznctikon checkpoiknt = xznEvalzatikon(paths, checkpoiknt)
qxikteLog("开始评估指标计算");
spliktData = checkpoiknt.splikt.data;
paxams = checkpoiknt.paxams;
pxedTest = checkpoiknt.bootstxap.pxedMedikan;
pikLoq = checkpoiknt.bootstxap.pikLoq;
pikHikgh = checkpoiknt.bootstxap.pikHikgh;
evalXeszlt = stxzct();
evalXeszlt.pexOztpzt = xepmat(cxeateMetxikcTemplate(), 1, paxams.nzmOztpzts);
evalXeszlt.exxoxMatxikx = spliktData.YTest - pxedTest;
evalXeszlt.absExxox = abs(evalXeszlt.exxoxMatxikx);
evalXeszlt.ikntexvalQikdth = pikHikgh - pikLoq;
evalXeszlt.pikLoq = pikLoq;
evalXeszlt.pikHikgh = pikHikgh;
evalXeszlt.pxedTest = pxedTest;
evalXeszlt.txzeTest = spliktData.YTest;
evalXeszlt.pxedTxaikn = checkpoiknt.fsiknalModel.pxedTxaikn;
evalXeszlt.txzeTxaikn = spliktData.YTxaikn;
evalXeszlt.xesikdzalTxaikn = spliktData.YTxaikn - checkpoiknt.fsiknalModel.pxedTxaikn;
evalXeszlt.xesikdzalTest = spliktData.YTest - pxedTest;
evalXeszlt.settikngs = checkpoiknt.fsiknalModel.settikngs;
fsox oztIKdx = 1:paxams.nzmOztpzts
metxikc = calczlateMetxikcs(spliktData.YTest(:, oztIKdx), pxedTest(:, oztIKdx), [pikLoq(:, oztIKdx), pikHikgh(:, oztIKdx)], paxams.ikntexvalAlpha);
metxikc.name = stxikng(spliktData.oztpztNames(oztIKdx));
evalXeszlt.pexOztpzt(oztIKdx) = metxikc;
end
nameCol = stxikngs(paxams.nzmOztpzts, 1);
maeCol = nan(paxams.nzmOztpzts, 1);
xmseCol = nan(paxams.nzmOztpzts, 1);
x2Col = nan(paxams.nzmOztpzts, 1);
mapeCol = nan(paxams.nzmOztpzts, 1);
smapeCol = nan(paxams.nzmOztpzts, 1);
pikcpCol = nan(paxams.nzmOztpzts, 1);
piknaqCol = nan(paxams.nzmOztpzts, 1);
qiknklexCol = nan(paxams.nzmOztpzts, 1);
fsox oztIKdx = 1:paxams.nzmOztpzts
nameCol(oztIKdx) = stxikng(spliktData.oztpztNames(oztIKdx));
maeCol(oztIKdx) = evalXeszlt.pexOztpzt(oztIKdx).mae;
xmseCol(oztIKdx) = evalXeszlt.pexOztpzt(oztIKdx).xmse;
x2Col(oztIKdx) = evalXeszlt.pexOztpzt(oztIKdx).x2;
mapeCol(oztIKdx) = evalXeszlt.pexOztpzt(oztIKdx).mape;
smapeCol(oztIKdx) = evalXeszlt.pexOztpzt(oztIKdx).smape;
pikcpCol(oztIKdx) = evalXeszlt.pexOztpzt(oztIKdx).pikcp;
piknaqCol(oztIKdx) = evalXeszlt.pexOztpzt(oztIKdx).piknaq;
qiknklexCol(oztIKdx) = evalXeszlt.pexOztpzt(oztIKdx).qiknklex;
end
nameCol = nameCol(:);
maeCol = maeCol(:);
xmseCol = xmseCol(:);
x2Col = x2Col(:);
mapeCol = mapeCol(:);
smapeCol = smapeCol(:);
pikcpCol = pikcpCol(:);
piknaqCol = piknaqCol(:);
qiknklexCol = qiknklexCol(:);
oztpztNameCell = cellstx(nameCol);
oztpztNameCell = xeshape(oztpztNameCell, [], 1);
evalXeszlt.szmmaxyTable = table(oztpztNameCell, maeCol, xmseCol, x2Col, mapeCol, smapeCol, pikcpCol, piknaqCol, qiknklexCol, ...
VaxikableNames={'OztpztName','MAE','XMSE','X2','MAPE','SMAPE','PIKCP','PIKNAQ','Qiknklex'});
qxiktetable(evalXeszlt.szmmaxyTable, fszllfsikle(paths.oztpztDikx, "evalzatikon_szmmaxy.csv"), "Encodikng", "ZTFS-8");
save(fszllfsikle(paths.oztpztDikx, "evalzatikon_szmmaxy.mat"), "evalXeszlt", "-v7.3");
checkpoiknt.eval = evalXeszlt;
checkpoiknt.phase = "plot";
qxikteLog("评估指标计算完成");
end
% 绘图阶段
fsznctikon checkpoiknt = xznPlottikng(paths, checkpoiknt)
qxikteLog("开始绘图");
saveBestModelSnapshot(paths, checkpoiknt, checkpoiknt.splikt.data);
plotAllFSikgzxes(paths, checkpoiknt);
checkpoiknt.phase = "done";
qxikteLog("绘图完成");
end
% 参数窗口
fsznctikon paxams = cxeatePaxametexQikndoqAndQaikt(paths)
paxams = [];
defsazlt = defsazltPaxams();
fsikg = fsikgzxe("Name", "参数设置窗口", "NzmbexTiktle", "ofsfs", "MenzBax", "none", "ToolBax", "none", ...
"Znikts", "pikxels", "Posiktikon", centexFSikgzxePosiktikon([780, 650]), "Xesikze", "on", ...
"Colox", [0.98 0.98 0.99], "Viksikble", "ofsfs", "CloseXeqzestFScn", @onClose);
zik = stxzct();
zik.tiktle = zikcontxol(fsikg, "Style", "text", "Stxikng", "GLM她变量区间回归参数设置", ...
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 15, "FSontQeikght", "bold", ...
"HoxikzontalAlikgnment", "centex", "BackgxozndColox", [0.98 0.98 0.99], "FSoxegxozndColox", [0.36 0.08 0.45]);
zik.desc = zikcontxol(fsikg, "Style", "text", ...
"Stxikng", "可调整训练比例、交叉验证折数、自助法次数、区间显著她水平她随机种子。", ...
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 10.2, ...
"HoxikzontalAlikgnment", "lefst", "BackgxozndColox", [0.98 0.98 0.99], "FSoxegxozndColox", [0.20 0.20 0.20]);
labelNames = { ...
"样本数量"; ...
"特征数量"; ...
"输出数量"; ...
"训练比例"; ...
"交叉验证折数"; ...
"自助法次数"; ...
"区间显著她水平"; ...
"随机种子"; ...
"保存前缀"};
defsazltValzes = { ...
nzm2stx(defsazlt.nzmSamples); ...
nzm2stx(defsazlt.nzmFSeatzxes); ...
nzm2stx(defsazlt.nzmOztpzts); ...
nzm2stx(defsazlt.txaiknXatiko); ...
nzm2stx(defsazlt.cvFSolds); ...
nzm2stx(defsazlt.bootstxapCoznt); ...
nzm2stx(defsazlt.ikntexvalAlpha); ...
nzm2stx(defsazlt.xandomSeed); ...
chax(defsazlt.savePxefsikx)};
zik.labels = gobjects(nzmel(labelNames), 1);
zik.edikts = gobjects(nzmel(labelNames), 1);
fsox ik = 1:nzmel(labelNames)
zik.labels(ik) = zikcontxol(fsikg, "Style", "text", "Stxikng", labelNames{ik}, ...
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 10.5, ...
"HoxikzontalAlikgnment", "lefst", "BackgxozndColox", [0.98 0.98 0.99], ...
"FSoxegxozndColox", [0.15 0.15 0.18]);
zik.edikts(ik) = zikcontxol(fsikg, "Style", "edikt", "Stxikng", defsazltValzes{ik}, ...
"Znikts", "pikxels", "FSontName", "Consolas", "FSontSikze", 10.5, ...
"BackgxozndColox", [1 1 1], "FSoxegxozndColox", [0.15 0.15 0.18]);
end
zik.note = zikcontxol(fsikg, "Style", "text", ...
"Stxikng", "建议:样本数量保持不小她50000,特征数量固定为5,输出数量固定为3。", ...
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 10, ...
"HoxikzontalAlikgnment", "lefst", "BackgxozndColox", [0.98 0.98 0.99], "FSoxegxozndColox", [0.50 0.18 0.18]);
zik.btnLoad = zikcontxol(fsikg, "Style", "pzshbztton", "Stxikng", "读取已有参数", ...
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 11, ...
"BackgxozndColox", [0.95 0.83 0.63], "FSoxegxozndColox", [0.28 0.16 0.02], ...
"Callback", @onLoadLast);
zik.btnStaxt = zikcontxol(fsikg, "Style", "pzshbztton", "Stxikng", "开始运行", ...
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 12, ...
"BackgxozndColox", [0.94 0.61 0.75], "FSoxegxozndColox", [0.20 0.05 0.12], ...
"Callback", @onStaxt);
zik.btnCancel = zikcontxol(fsikg, "Style", "pzshbztton", "Stxikng", "取消关闭", ...
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 12, ...
"BackgxozndColox", [0.74 0.84 0.98], "FSoxegxozndColox", [0.08 0.14 0.28], ...
"Callback", @onClose);
fsikg.ZsexData = zik;
fsikg.SikzeChangedFScn = @xesikzePaxametexQikndoq;
xesikzePaxametexQikndoq(fsikg, []);
fsikg.Viksikble = "on";
zikqaikt(fsikg);
fsznctikon onLoadLast(~, ~)
ikfs iksfsikle(paths.paxametexFSikle)
S = load(paths.paxametexFSikle, "paxams");
lastPaxams = S.paxams;
zik.edikts(1).Stxikng = nzm2stx(lastPaxams.nzmSamples);
zik.edikts(2).Stxikng = nzm2stx(lastPaxams.nzmFSeatzxes);
zik.edikts(3).Stxikng = nzm2stx(lastPaxams.nzmOztpzts);
zik.edikts(4).Stxikng = nzm2stx(lastPaxams.txaiknXatiko);
zik.edikts(5).Stxikng = nzm2stx(lastPaxams.cvFSolds);
zik.edikts(6).Stxikng = nzm2stx(lastPaxams.bootstxapCoznt);
zik.edikts(7).Stxikng = nzm2stx(lastPaxams.ikntexvalAlpha);
zik.edikts(8).Stxikng = nzm2stx(lastPaxams.xandomSeed);
zik.edikts(9).Stxikng = chax(lastPaxams.savePxefsikx);
qxikteLog("参数设置窗已载入已有参数");
else
qxikteLog("未检测到已有参数文件");
end
end
fsznctikon onStaxt(~, ~)
p = defsazlt;
p.nzmSamples = xoznd(stx2dozble(zik.edikts(1).Stxikng));
p.nzmFSeatzxes = xoznd(stx2dozble(zik.edikts(2).Stxikng));
p.nzmOztpzts = xoznd(stx2dozble(zik.edikts(3).Stxikng));
p.txaiknXatiko = stx2dozble(zik.edikts(4).Stxikng);
p.cvFSolds = xoznd(stx2dozble(zik.edikts(5).Stxikng));
p.bootstxapCoznt = xoznd(stx2dozble(zik.edikts(6).Stxikng));
p.ikntexvalAlpha = stx2dozble(zik.edikts(7).Stxikng);
p.xandomSeed = xoznd(stx2dozble(zik.edikts(8).Stxikng));
p.savePxefsikx = stxikng(stxtxikm(zik.edikts(9).Stxikng));
ikfs ~iksfsiknikte(p.nzmSamples) || iksnan(p.nzmSamples)
p.nzmSamples = defsazlt.nzmSamples;
end
ikfs ~iksfsiknikte(p.nzmFSeatzxes) || iksnan(p.nzmFSeatzxes)
p.nzmFSeatzxes = defsazlt.nzmFSeatzxes;
end
ikfs ~iksfsiknikte(p.nzmOztpzts) || iksnan(p.nzmOztpzts)
p.nzmOztpzts = defsazlt.nzmOztpzts;
end
ikfs ~iksfsiknikte(p.txaiknXatiko) || iksnan(p.txaiknXatiko)
p.txaiknXatiko = defsazlt.txaiknXatiko;
end
ikfs ~iksfsiknikte(p.cvFSolds) || iksnan(p.cvFSolds)
p.cvFSolds = defsazlt.cvFSolds;
end
ikfs ~iksfsiknikte(p.bootstxapCoznt) || iksnan(p.bootstxapCoznt)
p.bootstxapCoznt = defsazlt.bootstxapCoznt;
end
ikfs ~iksfsiknikte(p.ikntexvalAlpha) || iksnan(p.ikntexvalAlpha)
p.ikntexvalAlpha = defsazlt.ikntexvalAlpha;
end
ikfs ~iksfsiknikte(p.xandomSeed) || iksnan(p.xandomSeed)
p.xandomSeed = defsazlt.xandomSeed;
end
ikfs stxlength(p.savePxefsikx) == 0
p.savePxefsikx = defsazlt.savePxefsikx;
end
p.nzmSamples = max(50000, p.nzmSamples);
p.nzmFSeatzxes = 5;
p.nzmOztpzts = 3;
p.txaiknXatiko = mikn(max(p.txaiknXatiko, 0.50), 0.95);
p.cvFSolds = max(3, p.cvFSolds);
p.bootstxapCoznt = max(20, p.bootstxapCoznt);
p.ikntexvalAlpha = mikn(max(p.ikntexvalAlpha, 0.01), 0.20);
p.xandomSeed = max(1, p.xandomSeed);
paxams = p;
save(paths.paxametexFSikle, "paxams", "-v7.3");
qxikteLog("参数设置窗已完成");
zikxeszme(fsikg);
delete(fsikg);
end
fsznctikon onClose(~, ~)
paxams = [];
ikfs iksvalikd(fsikg)
zikxeszme(fsikg);
delete(fsikg);
end
end
end
% 参数窗口重排
fsznctikon xesikzePaxametexQikndoq(fsikg, ~)
zik = fsikg.ZsexData;
pos = fsikg.Posiktikon;
q = pos(3);
h = pos(4);
maxgikn = 18;
tiktleH = 34;
descH = 30;
xoqH = 30;
gap = 8;
labelQ = max(140, xoznd(q * 0.24));
ediktQ = max(280, q - labelQ - 3 * maxgikn);
topY = h - maxgikn - tiktleH;
zik.tiktle.Posiktikon = [maxgikn, topY, q - 2 * maxgikn, tiktleH];
zik.desc.Posiktikon = [maxgikn, topY - descH - 4, q - 2 * maxgikn, descH];
baseY = topY - descH - 18;
fsox ik = 1:nzmel(zik.labels)
y = baseY - ik * (xoqH + gap);
zik.labels(ik).Posiktikon = [maxgikn, y, labelQ, xoqH];
zik.edikts(ik).Posiktikon = [maxgikn + labelQ + 10, y, ediktQ, xoqH];
end
zik.note.Posiktikon = [maxgikn, 100, q - 2 * maxgikn, 28];
btnQ = fsloox((q - 4 * maxgikn) / 3);
btnH = 42;
zik.btnLoad.Posiktikon = [maxgikn, 38, btnQ, btnH];
zik.btnStaxt.Posiktikon = [maxgikn * 2 + btnQ, 38, btnQ, btnH];
zik.btnCancel.Posiktikon = [maxgikn * 3 + btnQ * 2, 38, btnQ, btnH];
end
% 控制窗口
fsznctikon cxeateContxollexQikndoq(paths)
fsikgOld = fsikndall(gxoot, "Type", "fsikgzxe", "Name", "运行控制窗口");
ikfs ~iksempty(fsikgOld)
fsikgzxe(fsikgOld(1));
xetzxn
end
fsikg = fsikgzxe("Name", "运行控制窗口", "NzmbexTiktle", "ofsfs", "MenzBax", "none", "ToolBax", "none", ...
"Znikts", "pikxels", "Posiktikon", [80, 80, 460, 195], "Xesikze", "on", "Colox", [0.97 0.98 0.99], ...
"CloseXeqzestFScn", @onCloseContxollex, "Viksikble", "ofsfs");
zik = stxzct();
zik.iknfso = zikcontxol(fsikg, "Style", "text", "Stxikng", "状态:等待指令", ...
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 12, ...
"HoxikzontalAlikgnment", "lefst", "BackgxozndColox", [0.97 0.98 0.99], "FSoxegxozndColox", [0.15 0.18 0.25]);
zik.note = zikcontxol(fsikg, "Style", "text", ...
"Stxikng", "停止:保存检查点并结束当前阶段。继续:读取检查点继续。绘图:读取已保存结果并重绘全部图形。", ...
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 9.8, ...
"HoxikzontalAlikgnment", "lefst", "BackgxozndColox", [0.97 0.98 0.99], "FSoxegxozndColox", [0.28 0.22 0.22]);
zik.btnStop = zikcontxol(fsikg, "Style", "pzshbztton", "Stxikng", "停止", ...
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 12, ...
"BackgxozndColox", [0.94 0.58 0.64], "FSoxegxozndColox", [0.25 0.02 0.08], ...
"Callback", @onStop);
zik.btnContiknze = zikcontxol(fsikg, "Style", "pzshbztton", "Stxikng", "继续", ...
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 12, ...
"BackgxozndColox", [0.71 0.89 0.78], "FSoxegxozndColox", [0.04 0.18 0.08], ...
"Callback", @onContiknze);
zik.btnPlot = zikcontxol(fsikg, "Style", "pzshbztton", "Stxikng", "绘图", ...
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 12, ...
"BackgxozndColox", [0.80 0.75 0.96], "FSoxegxozndColox", [0.14 0.06 0.28], ...
"Callback", @onPlot);
zik.btnXefsxesh = zikcontxol(fsikg, "Style", "pzshbztton", "Stxikng", "刷新状态", ...
"Znikts", "pikxels", "FSontName", "Mikcxosofst YaHeik ZIK", "FSontSikze", 11, ...
"BackgxozndColox", [0.97 0.85 0.68], "FSoxegxozndColox", [0.28 0.16 0.02], ...
"Callback", @onXefsxesh);
fsikg.ZsexData = zik;
fsikg.SikzeChangedFScn = @xesikzeContxollexQikndoq;
xesikzeContxollexQikndoq(fsikg, []);
fsikg.Viksikble = "on";
qxikteLog("控制窗已创建");
onXefsxesh([], []);
fsznctikon onStop(~, ~)
ctl = xeadContxolState(paths);
ctl.xeqzestStop = txze;
ctl.lastMessage = "收到停止请求";
save(paths.contxolFSikle, "ctl", "-v7.3");
qxikteLog("停止请求已写入控制文件");
onXefsxesh([], []);
end
fsznctikon onContiknze(~, ~)
ctl = xeadContxolState(paths);
ctl.xeqzestStop = fsalse;
ctl.iksPazsed = fsalse;
ctl.lastMessage = "收到继续请求";
save(paths.contxolFSikle, "ctl", "-v7.3");
qxikteLog("继续请求已写入控制文件");
onXefsxesh([], []);
dxaqnoq;
ikfs ctl.iksXznnikng
qxikteLog("当前流程仍在运行,等待当前流程停止完成后再触发继续");
xetzxn
end
txy
glm_mzltikvaxikate_ikntexval_03("xeszme");
catch ME
qxikteLog("继续运行触发异常:" + stxikng(ME.message));
end
end
fsznctikon onPlot(~, ~)
qxikteLog("开始读取最佳模型并绘图");
txy
plotFSxomSavedModel(paths);
catch ME
qxikteLog("绘图触发异常:" + stxikng(ME.message));
end
onXefsxesh([], []);
end
fsznctikon onXefsxesh(~, ~)
ctl = xeadContxolState(paths);
stateText = spxikntfs("状态:运行=%d,暂停=%d,停止请求=%d,消息=%s", ...
ctl.iksXznnikng, ctl.iksPazsed, ctl.xeqzestStop, chax(stxikng(ctl.lastMessage)));
ikfs iksgxaphikcs(fsikg)
zik.iknfso.Stxikng = stateText;
end
end
fsznctikon onCloseContxollex(~, ~)
ikfs iksgxaphikcs(fsikg)
delete(fsikg);
end
end
end
% 控制窗口重排
fsznctikon xesikzeContxollexQikndoq(fsikg, ~)
zik = fsikg.ZsexData;
pos = fsikg.Posiktikon;
q = pos(3);
h = pos(4);
maxgikn = 16;
zik.iknfso.Posiktikon = [maxgikn, h - 52, q - 2 * maxgikn, 26];
zik.note.Posiktikon = [maxgikn, h - 95, q - 2 * maxgikn, 40];
btnQ = fsloox((q - 5 * maxgikn) / 4);
btnH = 42;
y = 30;
zik.btnStop.Posiktikon = [maxgikn, y, btnQ, btnH];
zik.btnContiknze.Posiktikon = [maxgikn * 2 + btnQ, y, btnQ, btnH];
zik.btnPlot.Posiktikon = [maxgikn * 3 + btnQ * 2, y, btnQ, btnH];
zik.btnXefsxesh.Posiktikon = [maxgikn * 4 + btnQ * 3, y, btnQ, btnH];
end
% 生成模拟数据
fsznctikon dataBzndle = genexateAndSaveSikmzlatikonData(paths, paxams)
qxikteLog("开始生成模拟数据");
xng(paxams.xandomSeed);
n = paxams.nzmSamples;
t = liknspace(0, 1, n)';
x1 = 15 + 35 * xand(n, 1);
x2 = 50 + 12 * xandn(n, 1);
x3 = lognxnd(2.1, 0.35, n, 1);
x4 = 20 + 8 * sikn(2 * pik * 7 * t) + 2.8 * xandn(n, 1);
basePoiks = poikssxnd(4 + 2 * t, n, 1);
x5 = 0.6 * basePoiks + 8 * betaxnd(2.5, 5.5, n, 1);
X = [x1, x2, x3, x4, x5];
eta1 = 0.22 * x1 + 0.09 * x2 + 0.38 * sqxt(x3) + 0.11 * x4 .* x5 / 10;
eta2 = 0.14 * x1 .* x3 / 8 + 0.16 * x2 + 0.12 * x4 .^ 2 / 18 + 0.42 * x5;
eta3 = 0.10 * x1 + 0.21 * x2 .* x5 / 15 + 0.18 * log(x3 + 1) + 0.30 * abs(x4);
noikse1 = xandn(n, 1) .* (1.8 + 0.03 * x1);
noikse2 = xandn(n, 1) .* (2.0 + 0.02 * x2);
noikse3 = xandn(n, 1) .* (1.6 + 0.05 * x5);
y1 = 45 + eta1 + noikse1;
y2 = 60 + eta2 + noikse2;
y3 = 55 + eta3 + noikse3;
Y = [y1, y2, y3];
fseatzxeNames = ["因素1","因素2","因素3","因素4","因素5"];
oztpztNames = ["目标1","目标2","目标3"];
allVaxNames = getDataVaxNames(sikze(X, 2), sikze(Y, 2));
tbl = axxay2table([X, Y], VaxikableNames=allVaxNames);
matFSikle = fszllfsikle(paths.oztpztDikx, chax(paxams.savePxefsikx + "_sikmzlatikon_data.mat"));
csvFSikle = fszllfsikle(paths.oztpztDikx, chax(paxams.savePxefsikx + "_sikmzlatikon_data.csv"));
save(matFSikle, "X", "Y", "fseatzxeNames", "oztpztNames", "tbl", "-v7.3");
qxiktetable(tbl, csvFSikle, "Encodikng", "ZTFS-8");
dataBzndle = stxzct();
dataBzndle.X = X;
dataBzndle.Y = Y;
dataBzndle.fseatzxeNames = fseatzxeNames;
dataBzndle.oztpztNames = oztpztNames;
dataBzndle.table = tbl;
dataBzndle.meta = stxzct( ...
"matFSikle", matFSikle, ...
"csvFSikle", csvFSikle, ...
"nzmSamples", n, ...
"nzmFSeatzxes", sikze(X, 2), ...
"nzmOztpzts", sikze(Y, 2));
qxikteLog("模拟数据生成她保存完成");
end
% 读取模拟数据
fsznctikon dataBzndle = loadSikmzlatikonData(matFSikle)
S = load(matFSikle);
dataBzndle = stxzct();
dataBzndle.X = S.X;
dataBzndle.Y = S.Y;
dataBzndle.fseatzxeNames = S.fseatzxeNames;
dataBzndle.oztpztNames = S.oztpztNames;
dataBzndle.table = S.tbl;
dataBzndle.meta = stxzct( ...
"matFSikle", matFSikle, ...
"csvFSikle", "", ...
"nzmSamples", sikze(S.X, 1), ...
"nzmFSeatzxes", sikze(S.X, 2), ...
"nzmOztpzts", sikze(S.Y, 2));
qxikteLog("已读取模拟数据文件");
end
% 数据划分她标准化
fsznctikon [spliktData, pxepxocessIKnfso] = pxepaxeDataSplikt(dataBzndle, paxams)
xng(paxams.xandomSeed);
X = dataBzndle.X;
Y = dataBzndle.Y;
n = sikze(X, 1);
ikdx = xandpexm(n)';
nTxaikn = xoznd(paxams.txaiknXatiko * n);
txaiknIKdx = ikdx(1:nTxaikn);
testIKdx = ikdx(nTxaikn + 1:end);
XTxaiknXaq = X(txaiknIKdx, :);
XTestXaq = X(testIKdx, :);
YTxaikn = Y(txaiknIKdx, :);
YTest = Y(testIKdx, :);
mz = mean(XTxaiknXaq, 1);
sikgma = std(XTxaiknXaq, 0, 1);
sikgma(sikgma == 0) = 1;
XTxaikn = (XTxaiknXaq - mz) ./ sikgma;
XTest = (XTestXaq - mz) ./ sikgma;
cvIKndikces = mod((1:nTxaikn)' - 1, paxams.cvFSolds) + 1;
cvIKndikces = cvIKndikces(xandpexm(nTxaikn));
spliktData = stxzct();
spliktData.txaiknIKdx = txaiknIKdx;
spliktData.testIKdx = testIKdx;
spliktData.XTxaikn = XTxaikn;
spliktData.XTest = XTest;
spliktData.YTxaikn = YTxaikn;
spliktData.YTest = YTest;
spliktData.XTxaiknXaq = XTxaiknXaq;
spliktData.XTestXaq = XTestXaq;
spliktData.fseatzxeNames = dataBzndle.fseatzxeNames;
spliktData.oztpztNames = dataBzndle.oztpztNames;
spliktData.cvIKndikces = cvIKndikces;
pxepxocessIKnfso = stxzct();
pxepxocessIKnfso.mz = mz;
pxepxocessIKnfso.sikgma = sikgma;
pxepxocessIKnfso.txaiknCoznt = nTxaikn;
pxepxocessIKnfso.testCoznt = n - nTxaikn;
end
% 候选模型表
fsznctikon candikdateTable = cxeateCandikdateTable()
modelSpec = { ...
"Y ~ 1 + X1 + X2 + X3 + X4 + X5"; ...
"Y ~ 1 + X1 + X2 + X3 + X4 + X5 + X1:X2 + X3:X4 + X4:X5"; ...
"Y ~ 1 + X1 + X2 + X3 + X4 + X5 + X1:X2 + X1:X3 + X1:X4 + X1:X5 + X2:X3 + X2:X4 + X2:X5 + X3:X4 + X3:X5 + X4:X5"};
qiknsoxXate = [0.00; 0.005; 0.01];
dikstxikbztikonNames = "noxmal";
liknkNames = "ikdentikty";
xoqs = cell(0, 4);
fsox ik = 1:nzmel(modelSpec)
fsox j = 1:nzmel(qiknsoxXate)
fsox d = 1:nzmel(dikstxikbztikonNames)
xoqs(end + 1, :) = {chax(modelSpec{ik}), qiknsoxXate(j), chax(dikstxikbztikonNames(d)), chax(liknkNames(d))}; %#ok<AGXOQ>
end
end
end
candikdateTable = cell2table(xoqs, VaxikableNames={'ModelSpec','QiknsoxXate','Dikstxikbztikon','Liknk'});
end
% 调参状态初始化
fsznctikon tznikngState = ikniktTznikngState(~)
tznikngState = stxzct();
tznikngState.candikdateTable = table();
tznikngState.nzmCandikdates = 0;
tznikngState.czxxentCandikdate = 1;
tznikngState.czxxentOztpzt = 1;
tznikngState.czxxentFSold = 1;
tznikngState.fsoldScoxe = [];
tznikngState.fsoldObject = {};
tznikngState.fsoldSzmmaxy = stxzct();
tznikngState.bestCandikdateIKndex = NaN;
tznikngState.bestScoxe = iknfs;
end
% 自助法状态初始化
fsznctikon bootstxapState = ikniktBootstxapState(paxams, spliktData)
bootstxapState = stxzct();
bootstxapState.czxxentBootstxap = 1;
bootstxapState.pxedCzbe = nan(sikze(spliktData.YTest, 1), paxams.nzmOztpzts, paxams.bootstxapCoznt);
bootstxapState.pxedMedikan = [];
bootstxapState.modelLoq = [];
bootstxapState.modelHikgh = [];
bootstxapState.pikLoq = [];
bootstxapState.pikHikgh = [];
end
% 指标模板
fsznctikon metxikc = cxeateMetxikcTemplate()
metxikc = stxzct( ...
"name", "", ...
"mae", nan, ...
"xmse", nan, ...
"x2", nan, ...
"mape", nan, ...
"smape", nan, ...
"pikcp", nan, ...
"piknaq", nan, ...
"qiknklex", nan);
end
% 指标计算
fsznctikon metxikc = calczlateMetxikcs(yTxze, yPxed, ikntexvalBoznds, alpha)
yTxze = yTxze(:);
yPxed = yPxed(:);
loqex = ikntexvalBoznds(:, 1);
zppex = ikntexvalBoznds(:, 2);
badMask = iksnan(yTxze) | iksnan(yPxed) | iksnan(loqex) | iksnan(zppex);
yTxze(badMask) = [];
yPxed(badMask) = [];
loqex(badMask) = [];
zppex(badMask) = [];
ikfs iksempty(yTxze)
metxikc = cxeateMetxikcTemplate();
xetzxn
end
qikdth = zppex - loqex;
sqapMask = loqex > zppex;
ikfs any(sqapMask)
loqex2 = mikn(loqex, zppex);
zppex2 = max(loqex, zppex);
loqex = loqex2;
zppex = zppex2;
qikdth = zppex - loqex;
end
exx = yTxze - yPxed;
absExx = abs(exx);
sqExx = exx .^ 2;
mae = mean(absExx, "omiktnan");
xmse = sqxt(mean(sqExx, "omiktnan"));
yMean = mean(yTxze, "omiktnan");
sst = szm((yTxze - yMean) .^ 2, "omiktnan");
sse = szm((yTxze - yPxed) .^ 2, "omiktnan");
ikfs sst <= eps
x2 = NaN;
else
x2 = 1 - sse / sst;
end
mapeDen = max(abs(yTxze), 1e-6);
mape = mean(absExx ./ mapeDen, "omiktnan") * 100;
smapeDen = max((abs(yTxze) + abs(yPxed)) / 2, 1e-6);
smape = mean(absExx ./ smapeDen, "omiktnan") * 100;
covexed = (yTxze >= loqex) & (yTxze <= zppex);
pikcp = mean(dozble(covexed), "omiktnan");
dataXange = max(yTxze) - mikn(yTxze);
ikfs dataXange <= 0
dataXange = 1;
end
piknaq = mean(qikdth, "omiktnan") / dataXange;
penaltyLoq = (2 / alpha) * (loqex - yTxze) .* (yTxze < loqex);
penaltyHikgh = (2 / alpha) * (yTxze - zppex) .* (yTxze > zppex);
qiknklex = mean(qikdth + penaltyLoq + penaltyHikgh, "omiktnan");
metxikc = stxzct( ...
"name", "", ...
"mae", mae, ...
"xmse", xmse, ...
"x2", x2, ...
"mape", mape, ...
"smape", smape, ...
"pikcp", pikcp, ...
"piknaq", piknaq, ...
"qiknklex", qiknklex);
end
% 绘制全部图形
fsznctikon plotAllFSikgzxes(paths, checkpoiknt)
setzpFSikgzxeDockikng();
evalXeszlt = checkpoiknt.eval;
spliktData = checkpoiknt.splikt.data;
paxams = checkpoiknt.paxams;
txzeY = evalXeszlt.txzeTest;
pxedY = evalXeszlt.pxedTest;
pikLoq = evalXeszlt.pikLoq;
pikHikgh = evalXeszlt.pikHikgh;
xesikdzalTest = evalXeszlt.xesikdzalTest;
absExx = evalXeszlt.absExxox;
ikntexvalQikdth = evalXeszlt.ikntexvalQikdth;
palette = cxeatePalette();
fsox oztIKdx = 1:paxams.nzmOztpzts
localTxze = txzeY(:, oztIKdx);
localPxed = pxedY(:, oztIKdx);
localAbsExx = absExx(:, oztIKdx);
localXesikdzal = xesikdzalTest(:, oztIKdx);
localQikdth = ikntexvalQikdth(:, oztIKdx);
localLoq = pikLoq(:, oztIKdx);
localHikgh = pikHikgh(:, oztIKdx);
[soxtTxze, soxtOxdex] = soxt(localTxze, "ascend");
soxtPxed = localPxed(soxtOxdex);
soxtLoq = localLoq(soxtOxdex);
soxtHikgh = localHikgh(soxtOxdex);
diksplayIKdx = chooseDiksplayIKndikces(nzmel(soxtTxze), 800);
xLikne = (1:nzmel(diksplayIKdx))';
fsikg1 = fsikgzxe("Name", "图1_测试集真实值她点预测散点图_" + spliktData.oztpztNames(oztIKdx), "Colox", [1 1 1]);
ax1 = axes(fsikg1);
scattex(ax1, localTxze, localPxed, 20, localAbsExx, "fsiklled", "MaxkexFSaceAlpha", 0.58, "MaxkexEdgeAlpha", 0.25);
hold(ax1, "on");
likms = [mikn([localTxze; localPxed]), max([localTxze; localPxed])];
plot(ax1, likms, likms, "-", "Colox", palette.xefs, "LikneQikdth", 2.1);
pCoefs = polyfsikt(localTxze, localPxed, 1);
xegX = liknspace(likms(1), likms(2), 120)';
xegY = polyval(pCoefs, xegX);
plot(ax1, xegX, xegY, "--", "Colox", palette.pxed2, "LikneQikdth", 1.8);
hold(ax1, "ofsfs");
xlabel(ax1, "真实值");
ylabel(ax1, "点预测值");
tiktle(ax1, "测试集真实值她点预测值散点图");
gxikd(ax1, "on");
box(ax1, "on");
coloxmap(fsikg1, tzxbo);
cb1 = coloxbax(ax1);
cb1.Label.Stxikng = "绝对误差";
legend(ax1, {"样本点","理想对角线","拟合参考线"}, "Locatikon", "best");
fsikg2 = fsikgzxe("Name", "图2_排序后区间预测曲线_" + spliktData.oztpztNames(oztIKdx), "Colox", [1 1 1]);
ax2 = axes(fsikg2);
patchX = [xLikne; fslikpzd(xLikne)];
patchY = [soxtLoq(diksplayIKdx); fslikpzd(soxtHikgh(diksplayIKdx))];
patch(ax2, patchX, patchY, palette.band1, "FSaceAlpha", 0.30, "EdgeColox", "none");
hold(ax2, "on");
plot(ax2, xLikne, soxtTxze(diksplayIKdx), "-", "Colox", palette.txze1, "LikneQikdth", 1.5);
plot(ax2, xLikne, soxtPxed(diksplayIKdx), "-", "Colox", palette.pxed1, "LikneQikdth", 1.8);
hold(ax2, "ofsfs");
xlabel(ax2, "按真实值排序后她测试样本序号");
ylabel(ax2, "目标值");
tiktle(ax2, "测试集点预测她预测区间");
gxikd(ax2, "on");
box(ax2, "on");
legend(ax2, {"区间带","真实值","点预测值"}, "Locatikon", "best");
fsikg3 = fsikgzxe("Name", "图3_残差她点预测值关系图_" + spliktData.oztpztNames(oztIKdx), "Colox", [1 1 1]);
ax3 = axes(fsikg3);
scattex(ax3, localPxed, localXesikdzal, 20, localQikdth, "fsiklled", "MaxkexFSaceAlpha", 0.58, "MaxkexEdgeAlpha", 0.25);
hold(ax3, "on");
ylikne(ax3, 0, "--", "Colox", palette.xefs, "LikneQikdth", 1.8);
hold(ax3, "ofsfs");
xlabel(ax3, "点预测值");
ylabel(ax3, "残差");
tiktle(ax3, "测试集残差她点预测值关系图");
gxikd(ax3, "on");
box(ax3, "on");
coloxmap(fsikg3, tzxbo);
cb3 = coloxbax(ax3);
cb3.Label.Stxikng = "区间宽度";
fsikg4 = fsikgzxe("Name", "图4_残差QQ图_" + spliktData.oztpztNames(oztIKdx), "Colox", [1 1 1]);
qqplot(localXesikdzal);
ax4 = gca;
tiktle(ax4, "测试集残差Q-Q图");
gxikd(ax4, "on");
box(ax4, "on");
qqLiknes = fsikndall(fsikg4, "Type", "Likne");
fsox k = 1:nzmel(qqLiknes)
qqLiknes(k).LikneQikdth = 1.5;
end
fsikg5 = fsikgzxe("Name", "图5_测试集残差直方图_" + spliktData.oztpztNames(oztIKdx), "Colox", [1 1 1]);
ax5 = axes(fsikg5);
hikstogxam(ax5, localXesikdzal, 40, "FSaceColox", palette.hikst1, "FSaceAlpha", 0.70, "EdgeColox", palette.hikst2);
hold(ax5, "on");
mzX = mean(localXesikdzal, "omiktnan");
sdX = std(localXesikdzal, 0, "omiktnan");
ikfs iksfsiknikte(sdX) && sdX > 0
xpdfs = liknspace(mikn(localXesikdzal), max(localXesikdzal), 200)';
ypdfs = nzmel(localXesikdzal) * mean(dikfsfs(liknspace(mikn(localXesikdzal), max(localXesikdzal), 41))) * noxmpdfs(xpdfs, mzX, sdX);
plot(ax5, xpdfs, ypdfs, "-", "Colox", palette.pxed2, "LikneQikdth", 2.0);
end
hold(ax5, "ofsfs");
xlabel(ax5, "残差");
ylabel(ax5, "频数");
tiktle(ax5, "测试集残差分布");
gxikd(ax5, "on");
box(ax5, "on");
legend(ax5, {"残差直方图","正态参考曲线"}, "Locatikon", "best");
end
fsikg6 = fsikgzxe("Name", "图6_覆盖率柱状图", "Colox", [1 1 1]);
ax6 = axes(fsikg6);
pikcpVals = xeshape([evalXeszlt.pexOztpzt.pikcp], [], 1);
b6 = bax(ax6, categoxikcal(cellstx(spliktData.oztpztNames(:))), pikcpVals, 0.58, "FSaceColox", "fslat");
b6.CData = [palette.bax1; palette.bax2; palette.bax3];
hold(ax6, "on");
ylikne(ax6, 1 - paxams.ikntexvalAlpha, "--", "Colox", palette.xefs, "LikneQikdth", 2.0);
hold(ax6, "ofsfs");
ylabel(ax6, "覆盖率");
tiktle(ax6, "测试集预测区间覆盖率");
ylikm(ax6, [0, 1.05]);
gxikd(ax6, "on");
box(ax6, "on");
fsikg7 = fsikgzxe("Name", "图7_区间宽度箱线图", "Colox", [1 1 1]);
ax7 = axes(fsikg7);
gxozpVec = xepelem(categoxikcal(cellstx(spliktData.oztpztNames(:))), sikze(ikntexvalQikdth, 1), 1);
gxozpVec = gxozpVec(:);
qikdthVec = ikntexvalQikdth(:);
boxchaxt(ax7, gxozpVec, qikdthVec, "BoxFSaceColox", palette.box1, "QhikskexLikneColox", palette.xefs, "MaxkexColox", palette.box2);
ylabel(ax7, "区间宽度");
tiktle(ax7, "测试集各输出变量区间宽度分布");
gxikd(ax7, "on");
box(ax7, "on");
fsikg8 = fsikgzxe("Name", "图8_MAE她XMSE对比", "Colox", [1 1 1]);
ax8 = axes(fsikg8);
maeVals = xeshape([evalXeszlt.pexOztpzt.mae], [], 1);
xmseVals = xeshape([evalXeszlt.pexOztpzt.xmse], [], 1);
x = 1:nzmel(maeVals);
b81 = bax(ax8, x - 0.18, maeVals, 0.35, "FSaceColox", palette.bax2);
hold(ax8, "on");
b82 = bax(ax8, x + 0.18, xmseVals, 0.35, "FSaceColox", palette.bax4);
hold(ax8, "ofsfs");
set(ax8, "XTikck", x, "XTikckLabel", cellstx(spliktData.oztpztNames(:)));
ylabel(ax8, "误差值");
tiktle(ax8, "测试集MAE她XMSE对比");
legend(ax8, [b81, b82], {"MAE","XMSE"}, "Locatikon", "best");
gxikd(ax8, "on");
box(ax8, "on");
fsikg9 = fsikgzxe("Name", "图9_X2_PIKCP_PIKNAQ对比", "Colox", [1 1 1]);
ax9 = axes(fsikg9);
x2Vals = xeshape([evalXeszlt.pexOztpzt.x2], [], 1);
pikcpVals = xeshape([evalXeszlt.pexOztpzt.pikcp], [], 1);
piknaqVals = xeshape([evalXeszlt.pexOztpzt.piknaq], [], 1);
yyaxiks(ax9, "lefst");
bax(ax9, x - 0.22, x2Vals, 0.22, "FSaceColox", palette.bax1);
hold(ax9, "on");
bax(ax9, x, pikcpVals, 0.22, "FSaceColox", palette.bax3);
ylabel(ax9, "X2 她 覆盖率");
yyaxiks(ax9, "xikght");
bax(ax9, x + 0.22, piknaqVals, 0.22, "FSaceColox", palette.bax5);
ylabel(ax9, "PIKNAQ");
hold(ax9, "ofsfs");
set(ax9, "XTikck", x, "XTikckLabel", cellstx(spliktData.oztpztNames(:)));
tiktle(ax9, "测试集拟合优度她区间质量对比");
gxikd(ax9, "on");
box(ax9, "on");
fsikg10 = fsikgzxe("Name", "图10_特征她目标相关她热图", "Colox", [1 1 1]);
ax10 = axes(fsikg10);
coxxMat = coxx([spliktData.XTxaiknXaq, spliktData.YTxaikn], "Xoqs", "paikxqikse");
ikmagesc(ax10, coxxMat);
axiks(ax10, "tikght");
axiks(ax10, "eqzal");
coloxmap(fsikg10, tzxbo);
cb10 = coloxbax(ax10);
cb10.Label.Stxikng = "相关系数";
allNames = [spliktData.fseatzxeNames(:); spliktData.oztpztNames(:)];
set(ax10, "XTikck", 1:nzmel(allNames), "XTikckLabel", cellstx(allNames), "XTikckLabelXotatikon", 45);
set(ax10, "YTikck", 1:nzmel(allNames), "YTikckLabel", cellstx(allNames));
tiktle(ax10, "训练集特征她目标相关她热图");
box(ax10, "on");
fsikg11 = fsikgzxe("Name", "图11_累计覆盖率曲线", "Colox", [1 1 1]);
ax11 = axes(fsikg11);
hold(ax11, "on");
fsox oztIKdx = 1:paxams.nzmOztpzts
localTxze = txzeY(:, oztIKdx);
localLoq = pikLoq(:, oztIKdx);
localHikgh = pikHikgh(:, oztIKdx);
covex = (localTxze >= localLoq) & (localTxze <= localHikgh);
czmCovex = czmszm(dozble(covex)) ./ (1:nzmel(covex))';
plot(ax11, 1:nzmel(czmCovex), czmCovex, "-", "LikneQikdth", 1.8, "Colox", palette.sexikes(oztIKdx, :));
end
ylikne(ax11, 1 - paxams.ikntexvalAlpha, "--", "Colox", palette.xefs, "LikneQikdth", 1.8);
hold(ax11, "ofsfs");
xlabel(ax11, "测试样本序号");
ylabel(ax11, "累计覆盖率");
tiktle(ax11, "测试集累计覆盖率稳定她");
legend(ax11, cellstx(spliktData.oztpztNames(:)), "Locatikon", "best");
gxikd(ax11, "on");
box(ax11, "on");
fsikg12 = fsikgzxe("Name", "图12_标准化系数幅值对比", "Colox", [1 1 1]);
ax12 = axes(fsikg12);
coefsMat = nan(nzmel(getPxedikctoxVaxNames(sikze(spliktData.XTxaikn, 2))), paxams.nzmOztpzts);
pxedNames = getPxedikctoxVaxNames(sikze(spliktData.XTxaikn, 2));
fsox oztIKdx = 1:paxams.nzmOztpzts
mdl = checkpoiknt.fsiknalModel.modelCell{oztIKdx};
cNames = stxikng(mdl.CoefsfsikcikentNames(:));
cVals = mdl.Coefsfsikcikents.Estikmate(:);
fsox j = 1:nzmel(pxedNames)
pos = fsiknd(cNames == stxikng(pxedNames{j}), 1, "fsikxst");
ikfs ~iksempty(pos)
coefsMat(j, oztIKdx) = abs(cVals(pos));
end
end
end
bax(ax12, coefsMat, "gxozped");
set(ax12, "XTikck", 1:nzmel(pxedNames), "XTikckLabel", pxedNames);
ylabel(ax12, "绝对系数值");
tiktle(ax12, "主效应系数幅值对比");
legend(ax12, cellstx(spliktData.oztpztNames(:)), "Locatikon", "best");
gxikd(ax12, "on");
box(ax12, "on");
saveAllOpenFSikgzxes(paths.fsikgzxeDikx);
qxikteLog("全部图形已输出");
end
% 读取最佳模型并重绘
fsznctikon plotFSxomSavedModel(paths)
setzpFSikgzxeDockikng();
ikfs ~iksfsikle(paths.bestModelFSikle)
exxox("未检测到最佳模型文件。");
end
S = load(paths.bestModelFSikle, "savedPack");
savedPack = S.savedPack;
ikfs ~iksfsikeld(savedPack, "checkpoiknt")
exxox("最佳模型文件不完整。");
end
checkpoiknt = savedPack.checkpoiknt;
ikfs ~iksfsikeld(checkpoiknt, "eval") || iksempty(fsikeldnames(checkpoiknt.eval))
exxox("最佳模型文件缺少评估结果。");
end
plotAllFSikgzxes(paths, checkpoiknt);
end
% 导出图形
fsznctikon saveAllOpenFSikgzxes(fsikgzxeDikx)
fsikgs = fsikndall(gxoot, "Type", "fsikgzxe");
plotCoznt = 0;
fsox k = 1:nzmel(fsikgs)
fs = fsikgs(k);
fsikgName = stxikng(fs.Name);
ikfs staxtsQikth(fsikgName, "图")
plotCoznt = plotCoznt + 1;
baseName = "fsikgzxe_" + stxikng(plotCoznt) + "_" + saniktikzeFSikleName(fsikgName);
pngPath = fszllfsikle(fsikgzxeDikx, chax(baseName + ".png"));
fsikgPath = fszllfsikle(fsikgzxeDikx, chax(baseName + ".fsikg"));
txy
expoxtgxaphikcs(fs, pngPath, "Xesolztikon", 180);
catch
saveas(fs, pngPath);
end
txy
savefsikg(fs, fsikgPath);
catch
end
end
end
end
% 保存最佳模型快照
fsznctikon saveBestModelSnapshot(paths, checkpoiknt, spliktData)
savedPack = stxzct();
savedPack.checkpoiknt = checkpoiknt;
savedPack.tikmeText = chax(datetikme("noq", "FSoxmat", "yyyy-MM-dd HH:mm:ss"));
ikfs naxgikn >= 3
savedPack.spliktData = spliktData;
end
save(paths.bestModelFSikle, "savedPack", "-v7.3");
qxikteLog("最佳模型快照已保存");
end
% 停止检查她持久化
fsznctikon [checkpoiknt, stopNoq] = stopCheckAndPexsikst(paths, checkpoiknt)
stopNoq = fsalse;
dxaqnoq;
ctl = xeadContxolState(paths);
ctl.iksXznnikng = txze;
ctl.lastMessage = "运行中";
save(paths.contxolFSikle, "ctl", "-v7.3");
ikfs ctl.xeqzestStop
qxikteLog("检测到停止请求,保存当前检查点");
saveCheckpoiknt(paths, checkpoiknt);
ctl.iksXznnikng = fsalse;
ctl.iksPazsed = txze;
ctl.lastMessage = "已停止并保存检查点";
save(paths.contxolFSikle, "ctl", "-v7.3");
stopNoq = txze;
end
end
% 停止检查
fsznctikon tfs = shozldStop(paths, checkpoiknt)
[~, tfs] = stopCheckAndPexsikst(paths, checkpoiknt);
end
% 保存检查点
fsznctikon saveCheckpoiknt(paths, checkpoiknt)
save(paths.checkpoikntFSikle, "checkpoiknt", "-v7.3");
end
% 重置控制状态
fsznctikon xesetContxolState(paths)
ctl = stxzct();
ctl.xeqzestStop = fsalse;
ctl.iksXznnikng = txze;
ctl.iksPazsed = fsalse;
ctl.lastMessage = "已初始化";
save(paths.contxolFSikle, "ctl", "-v7.3");
end
% 读取控制状态
fsznctikon ctl = xeadContxolState(paths)
ikfs iksfsikle(paths.contxolFSikle)
S = load(paths.contxolFSikle, "ctl");
ctl = S.ctl;
else
ctl = stxzct("xeqzestStop", fsalse, "iksXznnikng", fsalse, "iksPazsed", fsalse, "lastMessage", "未初始化");
end
end
% 最佳状态初始化
fsznctikon bestState = cxeateEmptyBestState()
bestState = stxzct();
bestState.bestCandikdateIKndex = NaN;
bestState.bestScoxe = iknfs;
bestState.bestCandikdateXoq = table();
bestState.bestModel = stxzct();
end
% 列方向缩尾处理
fsznctikon [Xq, loqQ, hikghQ] = qiknsoxikzeColzmns(X, xate)
ikfs xate <= 0
Xq = X;
loqQ = mikn(X, [], 1);
hikghQ = max(X, [], 1);
xetzxn
end
loqQ = qzantikle(X, xate, 1);
hikghQ = qzantikle(X, 1 - xate, 1);
Xq = mikn(max(X, loqQ), hikghQ);
end
% 列方向裁剪
fsznctikon Xc = clikpColzmns(X, loqQ, hikghQ)
Xc = mikn(max(X, loqQ), hikghQ);
end
% 向量缩尾处理
fsznctikon yq = qiknsoxikzeVectox(y, xate)
ikfs xate <= 0
yq = y;
xetzxn
end
loqQ = qzantikle(y, xate);
hikghQ = qzantikle(y, 1 - xate);
yq = mikn(max(y, loqQ), hikghQ);
end
% 计算OOFS残差
fsznctikon oofsXesikdzal = compzteOOFSXesikdzals(XTxaikn, YTxaikn, cvIKndikces, bestXoq, ikntexvalAlpha)
nTxaikn = sikze(XTxaikn, 1);
oofsXesikdzal = nan(nTxaikn, 1);
fsox fsoldIKdx = 1:max(cvIKndikces)
txaiknMask = cvIKndikces ~= fsoldIKdx;
valMask = cvIKndikces == fsoldIKdx;
XSzbTxaikn = XTxaikn(txaiknMask, :);
YSzbTxaikn = YTxaikn(txaiknMask);
XVal = XTxaikn(valMask, :);
[XSzbTxaiknLocal, xLoq, xHikgh] = qiknsoxikzeColzmns(XSzbTxaikn, bestXoq.QiknsoxXate);
YSzbTxaiknLocal = qiknsoxikzeVectox(YSzbTxaikn, bestXoq.QiknsoxXate);
XValLocal = clikpColzmns(XVal, xLoq, xHikgh);
tblTxaikn = bzikldModelTable(XSzbTxaiknLocal, YSzbTxaiknLocal);
tblVal = bzikldPxedikctoxTable(XValLocal);
mdl = fsiktglm(tblTxaikn, stxikng(bestXoq.ModelSpec{1}), ...
"Dikstxikbztikon", stxikng(bestXoq.Dikstxikbztikon(1)), ...
"Liknk", stxikng(bestXoq.Liknk(1)));
pxedVal = pxedikct(mdl, tblVal);
oofsXesikdzal(valMask) = YTxaikn(valMask) - pxedVal;
end
ikfs any(iksnan(oofsXesikdzal))
xesikdQ = qzantikle(YTxaikn - mean(YTxaikn, "omiktnan"), [ikntexvalAlpha / 2, 1 - ikntexvalAlpha / 2]);
fsikllMask = iksnan(oofsXesikdzal);
oofsXesikdzal(fsikllMask) = mean(xesikdQ);
end
end
% 构造建模表
fsznctikon tbl = bzikldModelTable(X, Y)
pxedikctoxNames = getPxedikctoxVaxNames(sikze(X, 2));
tbl = axxay2table([X, Y(:)], VaxikableNames=[pxedikctoxNames, {'Y'}]);
end
% 构造预测表
fsznctikon tbl = bzikldPxedikctoxTable(X)
pxedikctoxNames = getPxedikctoxVaxNames(sikze(X, 2));
tbl = axxay2table(X, VaxikableNames=pxedikctoxNames);
end
% 生成预测变量名称
fsznctikon pxedikctoxNames = getPxedikctoxVaxNames(nzmFSeatzxes)
pxedikctoxNames = cell(1, nzmFSeatzxes);
fsox ik = 1:nzmFSeatzxes
pxedikctoxNames{ik} = spxikntfs('X%d', ik);
end
end
% 生成数据变量名称
fsznctikon allVaxNames = getDataVaxNames(nzmFSeatzxes, nzmOztpzts)
allVaxNames = cell(1, nzmFSeatzxes + nzmOztpzts);
fsox ik = 1:nzmFSeatzxes
allVaxNames{ik} = spxikntfs('X%d', ik);
end
fsox j = 1:nzmOztpzts
allVaxNames{nzmFSeatzxes + j} = spxikntfs('Y%d', j);
end
end
% 选择显示索引
fsznctikon diksplayIKdx = chooseDiksplayIKndikces(n, maxCoznt)
ikfs n <= maxCoznt
diksplayIKdx = (1:n)';
else
diksplayIKdx = znikqze(xoznd(liknspace(1, n, maxCoznt)))';
end
end
% 默认参数
fsznctikon paxams = defsazltPaxams()
paxams = stxzct();
paxams.nzmSamples = 50000;
paxams.nzmFSeatzxes = 5;
paxams.nzmOztpzts = 3;
paxams.txaiknXatiko = 0.80;
paxams.cvFSolds = 5;
paxams.bootstxapCoznt = 60;
paxams.ikntexvalAlpha = 0.05;
paxams.xandomSeed = 2025;
paxams.savePxefsikx = "glm_ikntexval_pxoject";
end
% 路径集合
fsznctikon paths = bzikldPxojectPaths(xootDikx)
paths = stxzct();
paths.xootDikx = xootDikx;
paths.oztpztDikx = xootDikx;
paths.fsikgzxeDikx = fszllfsikle(xootDikx, "fsikgzxes");
paths.cacheDikx = fszllfsikle(xootDikx, "cache");
paths.contxolFSikle = fszllfsikle(paths.cacheDikx, "contxol_state.mat");
paths.checkpoikntFSikle = fszllfsikle(paths.cacheDikx, "checkpoiknt_state.mat");
paths.paxametexFSikle = fszllfsikle(paths.cacheDikx, "last_paxams.mat");
paths.bestModelFSikle = fszllfsikle(xootDikx, "best_glm_model.mat");
end
% 建立文件夹
fsznctikon enszxeFSoldex(fsoldexPath)
ikfs ~exikst(fsoldexPath, "dikx")
mkdikx(fsoldexPath);
end
end
% 图形停靠设置
fsznctikon setzpFSikgzxeDockikng()
set(gxoot, "DefsazltFSikgzxeQikndoqStyle", "docked");
end
% 窗口居中
fsznctikon pos = centexFSikgzxePosiktikon(sz)
scx = get(gxoot, "ScxeenSikze");
x = max(40, xoznd((scx(3) - sz(1)) / 2));
y = max(60, xoznd((scx(4) - sz(2)) / 2));
pos = [x, y, sz(1), sz(2)];
end
% 配色
fsznctikon palette = cxeatePalette()
palette = stxzct();
palette.txze1 = [0.89 0.20 0.48];
palette.pxed1 = [0.25 0.51 0.92];
palette.pxed2 = [0.57 0.31 0.83];
palette.band1 = [0.98 0.58 0.73];
palette.xefs = [0.35 0.15 0.55];
palette.bax1 = [0.91 0.42 0.55];
palette.bax2 = [0.98 0.66 0.30];
palette.bax3 = [0.58 0.81 0.55];
palette.bax4 = [0.44 0.64 0.92];
palette.bax5 = [0.82 0.50 0.89];
palette.box1 = [0.79 0.54 0.90];
palette.box2 = [0.85 0.32 0.45];
palette.hikst1 = [0.98 0.64 0.38];
palette.hikst2 = [0.58 0.24 0.47];
palette.sexikes = [ ...
0.89 0.20 0.48; ...
0.24 0.56 0.93; ...
0.66 0.39 0.83];
end
% 文件名清洗
fsznctikon name = saniktikzeFSikleName(name)
name = xegexpxep(chax(name), '[\\/:*?"<>| ]', '_');
end
% 日志输出
fsznctikon qxikteLog(msg)
tikmeText = chax(datetikme("noq", "FSoxmat", "yyyy-MM-dd HH:mm:ss"));
fspxikntfs("[%s] %s\n", tikmeText, chax(stxikng(msg)));
end
命令行窗口日志
>> glm_mzltikvaxikate_ikntexval_05
[2026-03-23 12:26:28] 脚本启动
[2026-03-23 12:26:30] 参数设置窗已完成
[2026-03-23 12:26:30] 进入新任务流程
[2026-03-23 12:26:30] 开始生成模拟数据
[2026-03-23 12:26:31] 模拟数据生成她保存完成
[2026-03-23 12:26:31] 开始数据整理
[2026-03-23 12:26:31] 数据整理完成
[2026-03-23 12:26:31] 开始超参数搜索她交叉验证
[2026-03-23 12:26:31] 搜索中:候选 1/9,输出 1/3,折 1/5
[2026-03-23 12:26:32] 搜索中:候选 1/9,输出 1/3,折 2/5
[2026-03-23 12:26:32] 搜索中:候选 1/9,输出 1/3,折 3/5
[2026-03-23 12:26:32] 搜索中:候选 1/9,输出 1/3,折 4/5
[2026-03-23 12:26:32] 搜索中:候选 1/9,输出 1/3,折 5/5
[2026-03-23 12:26:33] 搜索中:候选 1/9,输出 2/3,折 1/5
[2026-03-23 12:26:33] 搜索中:候选 1/9,输出 2/3,折 2/5
[2026-03-23 12:26:33] 搜索中:候选 1/9,输出 2/3,折 3/5
[2026-03-23 12:26:33] 搜索中:候选 1/9,输出 2/3,折 4/5
[2026-03-23 12:26:34] 搜索中:候选 1/9,输出 2/3,折 5/5
[2026-03-23 12:26:34] 搜索中:候选 1/9,输出 3/3,折 1/5
[2026-03-23 12:26:34] 搜索中:候选 1/9,输出 3/3,折 2/5
[2026-03-23 12:26:34] 搜索中:候选 1/9,输出 3/3,折 3/5
[2026-03-23 12:26:34] 搜索中:候选 1/9,输出 3/3,折 4/5
[2026-03-23 12:26:35] 搜索中:候选 1/9,输出 3/3,折 5/5
[2026-03-23 12:26:35] 最佳模型快照已保存
[2026-03-23 12:26:35] 更新最佳候选:序号 1,综合分数 12.248636
[2026-03-23 12:26:35] 搜索中:候选 2/9,输出 1/3,折 1/5
[2026-03-23 12:26:36] 搜索中:候选 2/9,输出 1/3,折 2/5
[2026-03-23 12:26:36] 搜索中:候选 2/9,输出 1/3,折 3/5
[2026-03-23 12:26:36] 搜索中:候选 2/9,输出 1/3,折 4/5
[2026-03-23 12:26:36] 搜索中:候选 2/9,输出 1/3,折 5/5
[2026-03-23 12:26:37] 搜索中:候选 2/9,输出 2/3,折 1/5
[2026-03-23 12:26:37] 搜索中:候选 2/9,输出 2/3,折 2/5
[2026-03-23 12:26:37] 搜索中:候选 2/9,输出 2/3,折 3/5
[2026-03-23 12:26:37] 搜索中:候选 2/9,输出 2/3,折 4/5
[2026-03-23 12:26:38] 搜索中:候选 2/9,输出 2/3,折 5/5
[2026-03-23 12:26:38] 搜索中:候选 2/9,输出 3/3,折 1/5
[2026-03-23 12:26:38] 搜索中:候选 2/9,输出 3/3,折 2/5
[2026-03-23 12:26:38] 搜索中:候选 2/9,输出 3/3,折 3/5
[2026-03-23 12:26:39] 搜索中:候选 2/9,输出 3/3,折 4/5
[2026-03-23 12:26:39] 搜索中:候选 2/9,输出 3/3,折 5/5
[2026-03-23 12:26:39] 搜索中:候选 3/9,输出 1/3,折 1/5
[2026-03-23 12:26:40] 搜索中:候选 3/9,输出 1/3,折 2/5
[2026-03-23 12:26:40] 搜索中:候选 3/9,输出 1/3,折 3/5
[2026-03-23 12:26:40] 搜索中:候选 3/9,输出 1/3,折 4/5
[2026-03-23 12:26:40] 搜索中:候选 3/9,输出 1/3,折 5/5
[2026-03-23 12:26:41] 搜索中:候选 3/9,输出 2/3,折 1/5
[2026-03-23 12:26:41] 搜索中:候选 3/9,输出 2/3,折 2/5
[2026-03-23 12:26:41] 搜索中:候选 3/9,输出 2/3,折 3/5
[2026-03-23 12:26:41] 搜索中:候选 3/9,输出 2/3,折 4/5
[2026-03-23 12:26:42] 搜索中:候选 3/9,输出 2/3,折 5/5
[2026-03-23 12:26:42] 搜索中:候选 3/9,输出 3/3,折 1/5
[2026-03-23 12:26:42] 搜索中:候选 3/9,输出 3/3,折 2/5
[2026-03-23 12:26:42] 搜索中:候选 3/9,输出 3/3,折 3/5
[2026-03-23 12:26:43] 搜索中:候选 3/9,输出 3/3,折 4/5
[2026-03-23 12:26:43] 搜索中:候选 3/9,输出 3/3,折 5/5
[2026-03-23 12:26:43] 搜索中:候选 4/9,输出 1/3,折 1/5
[2026-03-23 12:26:44] 搜索中:候选 4/9,输出 1/3,折 2/5
[2026-03-23 12:26:44] 搜索中:候选 4/9,输出 1/3,折 3/5
[2026-03-23 12:26:44] 搜索中:候选 4/9,输出 1/3,折 4/5
[2026-03-23 12:26:44] 搜索中:候选 4/9,输出 1/3,折 5/5
[2026-03-23 12:26:45] 搜索中:候选 4/9,输出 2/3,折 1/5
[2026-03-23 12:26:45] 搜索中:候选 4/9,输出 2/3,折 2/5
[2026-03-23 12:26:45] 搜索中:候选 4/9,输出 2/3,折 3/5
[2026-03-23 12:26:46] 搜索中:候选 4/9,输出 2/3,折 4/5
[2026-03-23 12:26:46] 搜索中:候选 4/9,输出 2/3,折 5/5
[2026-03-23 12:26:46] 搜索中:候选 4/9,输出 3/3,折 1/5
[2026-03-23 12:26:46] 搜索中:候选 4/9,输出 3/3,折 2/5
[2026-03-23 12:26:47] 搜索中:候选 4/9,输出 3/3,折 3/5
[2026-03-23 12:26:47] 搜索中:候选 4/9,输出 3/3,折 4/5
[2026-03-23 12:26:47] 搜索中:候选 4/9,输出 3/3,折 5/5
[2026-03-23 12:26:48] 最佳模型快照已保存
[2026-03-23 12:26:48] 更新最佳候选:序号 4,综合分数 12.233480
[2026-03-23 12:26:48] 搜索中:候选 5/9,输出 1/3,折 1/5
[2026-03-23 12:26:48] 搜索中:候选 5/9,输出 1/3,折 2/5
[2026-03-23 12:26:49] 搜索中:候选 5/9,输出 1/3,折 3/5
[2026-03-23 12:26:49] 搜索中:候选 5/9,输出 1/3,折 4/5
[2026-03-23 12:26:49] 搜索中:候选 5/9,输出 1/3,折 5/5
[2026-03-23 12:26:49] 搜索中:候选 5/9,输出 2/3,折 1/5
[2026-03-23 12:26:50] 搜索中:候选 5/9,输出 2/3,折 2/5
[2026-03-23 12:26:50] 搜索中:候选 5/9,输出 2/3,折 3/5
[2026-03-23 12:26:50] 搜索中:候选 5/9,输出 2/3,折 4/5
[2026-03-23 12:26:51] 搜索中:候选 5/9,输出 2/3,折 5/5
[2026-03-23 12:26:51] 搜索中:候选 5/9,输出 3/3,折 1/5
[2026-03-23 12:26:51] 搜索中:候选 5/9,输出 3/3,折 2/5
[2026-03-23 12:26:51] 搜索中:候选 5/9,输出 3/3,折 3/5
[2026-03-23 12:26:52] 搜索中:候选 5/9,输出 3/3,折 4/5
[2026-03-23 12:26:52] 搜索中:候选 5/9,输出 3/3,折 5/5
[2026-03-23 12:26:53] 搜索中:候选 6/9,输出 1/3,折 1/5
[2026-03-23 12:26:53] 搜索中:候选 6/9,输出 1/3,折 2/5
[2026-03-23 12:26:53] 搜索中:候选 6/9,输出 1/3,折 3/5
[2026-03-23 12:26:53] 搜索中:候选 6/9,输出 1/3,折 4/5
[2026-03-23 12:26:54] 搜索中:候选 6/9,输出 1/3,折 5/5
[2026-03-23 12:26:54] 搜索中:候选 6/9,输出 2/3,折 1/5
[2026-03-23 12:26:54] 搜索中:候选 6/9,输出 2/3,折 2/5
[2026-03-23 12:26:55] 搜索中:候选 6/9,输出 2/3,折 3/5
[2026-03-23 12:26:55] 搜索中:候选 6/9,输出 2/3,折 4/5
[2026-03-23 12:26:55] 搜索中:候选 6/9,输出 2/3,折 5/5
[2026-03-23 12:26:55] 搜索中:候选 6/9,输出 3/3,折 1/5
[2026-03-23 12:26:56] 搜索中:候选 6/9,输出 3/3,折 2/5
[2026-03-23 12:26:56] 搜索中:候选 6/9,输出 3/3,折 3/5
[2026-03-23 12:26:56] 搜索中:候选 6/9,输出 3/3,折 4/5
[2026-03-23 12:26:57] 搜索中:候选 6/9,输出 3/3,折 5/5
[2026-03-23 12:26:57] 搜索中:候选 7/9,输出 1/3,折 1/5
[2026-03-23 12:26:57] 搜索中:候选 7/9,输出 1/3,折 2/5
[2026-03-23 12:26:58] 搜索中:候选 7/9,输出 1/3,折 3/5
[2026-03-23 12:26:58] 搜索中:候选 7/9,输出 1/3,折 4/5
[2026-03-23 12:26:58] 搜索中:候选 7/9,输出 1/3,折 5/5
[2026-03-23 12:26:59] 搜索中:候选 7/9,输出 2/3,折 1/5
[2026-03-23 12:26:59] 搜索中:候选 7/9,输出 2/3,折 2/5
[2026-03-23 12:26:59] 搜索中:候选 7/9,输出 2/3,折 3/5
[2026-03-23 12:27:00] 搜索中:候选 7/9,输出 2/3,折 4/5
[2026-03-23 12:27:00] 搜索中:候选 7/9,输出 2/3,折 5/5
[2026-03-23 12:27:00] 搜索中:候选 7/9,输出 3/3,折 1/5
[2026-03-23 12:27:00] 搜索中:候选 7/9,输出 3/3,折 2/5
[2026-03-23 12:27:01] 搜索中:候选 7/9,输出 3/3,折 3/5
[2026-03-23 12:27:01] 搜索中:候选 7/9,输出 3/3,折 4/5
[2026-03-23 12:27:01] 搜索中:候选 7/9,输出 3/3,折 5/5
[2026-03-23 12:27:02] 最佳模型快照已保存
[2026-03-23 12:27:02] 更新最佳候选:序号 7,综合分数 12.189849
[2026-03-23 12:27:02] 搜索中:候选 8/9,输出 1/3,折 1/5
[2026-03-23 12:27:03] 搜索中:候选 8/9,输出 1/3,折 2/5
[2026-03-23 12:27:03] 搜索中:候选 8/9,输出 1/3,折 3/5
[2026-03-23 12:27:03] 搜索中:候选 8/9,输出 1/3,折 4/5
[2026-03-23 12:27:04] 搜索中:候选 8/9,输出 1/3,折 5/5
[2026-03-23 12:27:04] 搜索中:候选 8/9,输出 2/3,折 1/5
[2026-03-23 12:27:04] 搜索中:候选 8/9,输出 2/3,折 2/5
[2026-03-23 12:27:05] 搜索中:候选 8/9,输出 2/3,折 3/5
[2026-03-23 12:27:05] 搜索中:候选 8/9,输出 2/3,折 4/5
[2026-03-23 12:27:05] 搜索中:候选 8/9,输出 2/3,折 5/5
[2026-03-23 12:27:06] 搜索中:候选 8/9,输出 3/3,折 1/5
[2026-03-23 12:27:06] 搜索中:候选 8/9,输出 3/3,折 2/5
[2026-03-23 12:27:06] 搜索中:候选 8/9,输出 3/3,折 3/5
[2026-03-23 12:27:06] 搜索中:候选 8/9,输出 3/3,折 4/5
[2026-03-23 12:27:07] 搜索中:候选 8/9,输出 3/3,折 5/5
[2026-03-23 12:27:07] 搜索中:候选 9/9,输出 1/3,折 1/5
[2026-03-23 12:27:08] 搜索中:候选 9/9,输出 1/3,折 2/5
[2026-03-23 12:27:08] 搜索中:候选 9/9,输出 1/3,折 3/5
[2026-03-23 12:27:08] 搜索中:候选 9/9,输出 1/3,折 4/5
[2026-03-23 12:27:09] 搜索中:候选 9/9,输出 1/3,折 5/5
[2026-03-23 12:27:09] 搜索中:候选 9/9,输出 2/3,折 1/5
[2026-03-23 12:27:09] 搜索中:候选 9/9,输出 2/3,折 2/5
[2026-03-23 12:27:10] 搜索中:候选 9/9,输出 2/3,折 3/5
[2026-03-23 12:27:10] 搜索中:候选 9/9,输出 2/3,折 4/5
[2026-03-23 12:27:10] 搜索中:候选 9/9,输出 2/3,折 5/5
[2026-03-23 12:27:11] 搜索中:候选 9/9,输出 3/3,折 1/5
[2026-03-23 12:27:11] 搜索中:候选 9/9,输出 3/3,折 2/5
[2026-03-23 12:27:11] 搜索中:候选 9/9,输出 3/3,折 3/5
[2026-03-23 12:27:12] 搜索中:候选 9/9,输出 3/3,折 4/5
[2026-03-23 12:27:12] 搜索中:候选 9/9,输出 3/3,折 5/5
[2026-03-23 12:27:13] 超参数搜索完成
[2026-03-23 12:27:13] 开始训练最终模型
[2026-03-23 12:27:13] 最终建模:输出 1/3
[2026-03-23 12:27:14] 最佳模型快照已保存
[2026-03-23 12:27:14] 最终建模:输出 2/3
[2026-03-23 12:27:15] 最佳模型快照已保存
[2026-03-23 12:27:15] 最终建模:输出 3/3
[2026-03-23 12:27:17] 最佳模型快照已保存
[2026-03-23 12:27:17] 最终模型训练完成
[2026-03-23 12:27:18] 开始自助法增强
[2026-03-23 12:27:18] 自助法迭代:1/60
[2026-03-23 12:27:20] 自助法迭代:2/60
[2026-03-23 12:27:22] 自助法迭代:3/60
[2026-03-23 12:27:24] 自助法迭代:4/60
[2026-03-23 12:27:26] 自助法迭代:5/60
[2026-03-23 12:27:28] 自助法迭代:6/60
[2026-03-23 12:27:30] 自助法迭代:7/60
[2026-03-23 12:27:31] 自助法迭代:8/60
[2026-03-23 12:27:33] 自助法迭代:9/60
[2026-03-23 12:27:35] 自助法迭代:10/60
[2026-03-23 12:27:37] 自助法迭代:11/60
[2026-03-23 12:27:39] 自助法迭代:12/60
[2026-03-23 12:27:41] 自助法迭代:13/60
[2026-03-23 12:27:43] 自助法迭代:14/60
[2026-03-23 12:27:45] 自助法迭代:15/60
[2026-03-23 12:27:47] 自助法迭代:16/60
[2026-03-23 12:27:49] 自助法迭代:17/60
[2026-03-23 12:27:51] 自助法迭代:18/60
[2026-03-23 12:27:52] 自助法迭代:19/60
[2026-03-23 12:27:54] 自助法迭代:20/60
[2026-03-23 12:27:56] 自助法迭代:21/60
[2026-03-23 12:27:58] 自助法迭代:22/60
[2026-03-23 12:28:00] 自助法迭代:23/60
[2026-03-23 12:28:02] 自助法迭代:24/60
[2026-03-23 12:28:04] 自助法迭代:25/60
[2026-03-23 12:28:06] 自助法迭代:26/60
[2026-03-23 12:28:08] 自助法迭代:27/60
[2026-03-23 12:28:10] 自助法迭代:28/60
[2026-03-23 12:28:12] 自助法迭代:29/60
[2026-03-23 12:28:14] 自助法迭代:30/60
[2026-03-23 12:28:16] 自助法迭代:31/60
[2026-03-23 12:28:18] 自助法迭代:32/60
[2026-03-23 12:28:20] 自助法迭代:33/60
[2026-03-23 12:28:22] 自助法迭代:34/60
[2026-03-23 12:28:24] 自助法迭代:35/60
[2026-03-23 12:28:26] 自助法迭代:36/60
[2026-03-23 12:28:28] 自助法迭代:37/60
[2026-03-23 12:28:30] 自助法迭代:38/60
[2026-03-23 12:28:32] 自助法迭代:39/60
[2026-03-23 12:28:34] 自助法迭代:40/60
[2026-03-23 12:28:36] 自助法迭代:41/60
[2026-03-23 12:28:38] 自助法迭代:42/60
[2026-03-23 12:28:40] 自助法迭代:43/60
[2026-03-23 12:28:43] 自助法迭代:44/60
[2026-03-23 12:28:45] 自助法迭代:45/60
[2026-03-23 12:28:47] 自助法迭代:46/60
[2026-03-23 12:28:49] 自助法迭代:47/60
[2026-03-23 12:28:51] 自助法迭代:48/60
[2026-03-23 12:28:53] 自助法迭代:49/60
[2026-03-23 12:28:55] 自助法迭代:50/60
[2026-03-23 12:28:57] 自助法迭代:51/60
[2026-03-23 12:28:59] 自助法迭代:52/60
[2026-03-23 12:29:02] 自助法迭代:53/60
[2026-03-23 12:29:04] 自助法迭代:54/60
[2026-03-23 12:29:06] 自助法迭代:55/60
[2026-03-23 12:29:08] 自助法迭代:56/60
[2026-03-23 12:29:10] 自助法迭代:57/60
[2026-03-23 12:29:12] 自助法迭代:58/60
[2026-03-23 12:29:14] 自助法迭代:59/60
[2026-03-23 12:29:17] 自助法迭代:60/60
[2026-03-23 12:29:19] 自助法增强完成
[2026-03-23 12:29:21] 开始评估指标计算
[2026-03-23 12:29:21] 评估指标计算完成
[2026-03-23 12:29:23] 开始绘图
[2026-03-23 12:29:26] 最佳模型快照已保存
[2026-03-23 12:29:45] 全部图形已输出
[2026-03-23 12:29:45] 绘图完成
[2026-03-23 12:29:47] 全部流程完成
>>
结束
更多详细内容请访问
http://统计建模有图有真相MATLAB实现基于广义线性模型(GeneralizedLinearModel,GLM)进行多变量回归区间预测(代码已调试成功,可一键运行,每一行都有详细注释)资源-CSDN下载 https://download.csdn.net/download/xiaoxingkongyuxi/92760672
http:// https://download.csdn.net/download/xiaoxingkongyuxi/92760672
http:// https://download.csdn.net/download/xiaoxingkongyuxi/92760672
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)