news 2026/9/24 1:07:29

MATLAB基于决策树的空气质量分析与AQI等级预测

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MATLAB基于决策树的空气质量分析与AQI等级预测

简介:基于MATLAB的决策树空气质量分析源码,面向环境监测、科研及高校相关专业学生,提供从数据预处理、模型训练到可视化分析的一整套实现方案。资源共150个文件,压缩包约14.21MB,其中58个m脚本为核心算法代码,14个mat为环境及污染物数据集,另有fig交互图、jpg/png结果图、pdf/xlsx/docx文档和论文材料,覆盖建模、测试与成果整理全流程。该资源针对AQI分类预测场景,以温度、湿度、风速及PM2.5、PM10、NO2等为输入特征,完整实现了数据清洗、标准化归一化、离散化等预处理步骤,并基于ClassificationTree/TreeBagger等决策树算法完成模型训练与交叉验证,配有毕设论文、小论文、UI交互界面及多张训练结果图,便于理解算法原理并支持二次开发。目前已有51人学习下载,适合需要完成空气质量分析课题、课设或毕设的MATLAB使用者。

1. matlab基于决策树的空气质量分析:为什么这个方案最容易落地

拿到城市一年的空气质量监测数据,想用它做分析或预测,手边只有matlab,这是很多环境类课程设计、毕业论文和业务侧小项目的真实起点。matlab基于决策树的空气质量分析,核心就是一句话:用fitctree在PM2.5、SO2、NO2、O3等浓度特征上长出一棵决策树,让它解释AQI等级怎么来的、哪些因子影响最大。决策树不是精度最高的方法,但它是所有模型里最不黑匣子的那个:树能画出来、规则能读出来、特征重要度能排出来,答辩、评审和管理人员都愿意跟进。这篇笔记适合两类人:手里有源码包但跑不通、想搞懂每行代码在干什么的初学者,以及模型调不准、想弄清边界参数和踩坑点的熟手。下面不吹精度,只讲能落地的流程。

2. 决策树凭什么适合空气质量数据:原理、剪枝与模型选型

2.1 可解释性是环境分析的第一需求

空气质量分析有个特殊约束:模型不只用来预测,还要用来说服人。环保部门的人、论文评审、课程答辩老师,都不会只凭一个预测数值就信任黑匣子。决策树恰恰把推理过程摊在桌面上——从根节点开始,每一步都用“PM2.5浓度大于75就走向左子树”这种明确的阈值判断分流,直到叶子节点给出“轻度污染”之类的结论。整个决策链条可以被任何人复查,这是神经网络和普通支持向量机给不了的。

这个特性在污染溯源和预警方案里尤其有用。比如分析结论想论证“夏季臭氧主导了污染等级”,决策树的高频分裂特征直接把O3摆在树的浅层位置,不用额外做SHAP或其他解释性分析。对于本科毕业论文或环境监测站的分析报告,能画出一棵带阈值的树,解释成本远低于深度学习方案。回答“谁影响最大”和“阈值是多少”这两个问题,决策树几乎是最直接的工具。

另外,matlab在统计与机器学习工具箱里内置了决策树的完整实现,fitctree一行就能建树、predict一行就能预测,不需要额外安装任何第三方依赖。这也是大量历史源码包选择决策树而不是xgboost或LightGBM的原因:发布时间早、依赖少、跨版本兼容性好。从“拿到源码能跑”这个务实目标出发,决策树是最稳的落点,不会因为缺某个运行库而卡在第一步。

2.2 基尼系数与CART树的生长机制

matlab里fitctree实现的是CART算法,也就是分类与回归树,分类场景默认用基尼系数作为分裂准则。基尼系数衡量一个节点里的“不纯度”:假设某个节点里有20条样本,12条属于“优”类,8条属于“良”类,那么这个节点的基尼系数是Gini = 1 - (12/20)^2 - (8/20)^2 = 0.48。基尼系数越小,代表节点里的样本类别越集中、越“纯”。树的生长过程就是每个节点遍历所有特征、尝试所有可能的切分阈值,找到那个让分裂后子节点加权基尼下降最多的特征和阈值,然后一分为二,递归进行。

空气质量数据有个典型特点:不同特征量纲差异非常大。CO浓度往往是每立方米零点几到几毫克,PM2.5和PM10能到几百微克,如果换用基于距离的模型,必须做标准化或归一化。但决策树是阈值切分模型,特征的绝对量级不影响分裂结果,也不需要对特征做单调变换。这个特性省掉了一大段预处理环节,也是它适合直接用原始监测数据建模的重要原因。

CART树默认会一直长到不能再分,极端情况下每个叶子节点只剩一条样本,训练精度能到100%,但换到新数据上精度崩盘。所以fitctree内部默认开启剪枝,把那些对验证集精度没有贡献的枝条剪掉。实际操作中我一般不太依赖事后剪枝,而是更信任两个前置限制:MaxNumSplits限制整棵树的分裂次数上限,MinLeafSize限制每个叶子节点的最少样本数。这两个参数比剪枝更直观、更容易解释给非技术读者听,后文会给出具体调法。

2.3 分类还是回归:AQI等级或污染物浓度怎么选

“空气质量分析”听起来是一个问题,真正动手建模前必须先回答:标签是离散等级还是连续数值。如果目标是预测明天的AQI等级,就把AQI数值映射到优、良、轻度污染、中度污染、重度污染、严重污染这六个等级,用fitctree做多分类;如果目标是报出下一小时PM2.5的具体浓度,用fitrtree做回归。

选型直接影响评价口径。分类模型看混淆矩阵,算每一类的查准率和查全率,关心哪些等级容易被误判成相邻等级;回归模型看RMSE、MAE和R方,关心预测值和真实值之间的误差分布。我的经验是:给环境管理部门写分析报告时优先做等级分类,因为管理动作本身就是按等级触发的——达到某个级别才启动预警、限产或应急预案,决策树分类结果天然可以对照管理阈值。而做论文的算法对比部分,回归分析有时更有讲头,能画误差曲线、能讨论不确定性;但解释性上明显弱于分类。

还有个折中做法:先按等级分类建模,再把分类结果里的主要误判方向拎出来做回归,两者结合,既能解释又能量化。对一套课程设计或周期很紧的专题分析来说,先分类后回归的顺序,比一上来就钻回归更容易出成果。

2.4 单棵决策树还是随机森林:边界的判断

随机森林和决策树的区别,一句话就能讲清:随机森林训练上百棵树,让它们投票取多数,方差更低、精度通常更高;但单棵决策树可解释性更强,可以直接画出结构、读出规则。在matlab里切换成本极低,fitctree换到fitcensemble再指定Bag方法就是随机森林,但两者的使用场景并不相同。

我判断选型时看三个条件。第一,有没有人需要看懂模型逻辑——答辩、写报告、给领导汇报,选单棵决策树,因为你能指着树说“这里分了叉,规则是什么”;第二,样本量是否足够大——几千条数据时随机森林的精度优势有限,单树复现和讲解都轻松很多;第三,有没有条件做超参搜索——随机森林一旦搜起来,每个候选模型要训练上百棵树,几十个组合下来笔记本风扇直接起飞,时间和算力成本高一个量级。

所以实际工作流我会建议先用单棵决策树跑通基线和特征有效性,确认六个监测因子确实和AQI等级相关,再决定要不要上随机森林。单纯为了刷那两三个百分点的精度去换不可解释性,在环境业务里往往不划算。本篇主题是单棵决策树的完整落地,先把这条路走通,后面想换森林时,改模型那两行代码反而是最简单的部分。

3. 空气质量数据预处理:字段含义、缺失值清洗与标签构造

3.1 拿到源码包先核对三件事:路径、列名、标签定义

不管这个源码包是你自己写的还是从网上下载的,在点运行之前,先打开主脚本核对三件事,能避开大部分“跑不通”的问题。

第一,数据文件用什么加载的。readtable对应csv或xlsx,load对应mat文件,代码里写的文件名和路径必须真实存在。matlab的当前工作目录和脚本所在目录经常不是同一个,这类路径问题占源码跑不通原因的很大比例。第二,列名是什么。readtable会自动把csv表头转成合法字段名,特殊字符变成下划线,所以在csv里写的是PM2.5,读进来可能变成PM2_5,原脚本如果还引用data.PM2.5就会直接报错。第三,标签列是原始浓度数值还是已经切好的等级。这两种情况模型入口完全不同,前者要回归、后者要分类,切分逻辑也会写在不同位置。

这三件事看起来琐碎,但决定了你能不能把精力集中在算法上面。很多“源码下载下来跑不通”的案例,问题根本不在决策树,而在数据加载的这几行兼容性上。拿到任何新数据集,前十分钟都值得花在核对表结构上,而不是急着跑模型。

3.2 用readtable加载原始数据并统一时间轴

典型的数据来源是环境监测公开接口或历年城市空气质量日度报表,落地成csv后一般长这样:

time,SO2,NO2,CO,O3,PM2_5,PM10,AQI 2023-01-01,9,34,0.7,48,28,53,47 2023-01-02,11,41,0.8,52,36,62,55

注意PM2_5是下划线而不是点,这正是readtable规则转换后的样子。加载进matlab的第一件事不是直接开始训练,而是把时间列从文本转成datetime类型,并按时间排序。

data = readtable('air_quality.csv'); data.time = datetime(data.time, 'InputFormat', 'yyyy-MM-dd'); data = sortrows(data, 'time');

这段代码有两点值得说。readtable自动识别csv表头生成datetime列,但如果时间格式是“2023/1/1”这种非零填充写法,InputFormat要改成'yyyy/M/d',否则转出来的全是NaT缺失值。sortrows按时间排序是为了后续按时间顺序切分训练集和验证集,这一步漏掉的话,后面所有切分都是错序的。另一个容易忽略的问题是重复时间戳。同一个监测日出现两次的情况并不少见,先跑一次unique(data.time)检查重复,比训练结束后对着诡异结果排查要省事得多。

时间轴统一之后,下一步是检查数据跨度。如果只有几个月的记录,叶子节点的样本数量会非常紧张,模型很难学到稳定的季节规律。我一般至少要求有连续12个月以上的日度数据,少于这个量级,建议把“预测”改成“分类解释”,别硬上时间预测。

3.3 缺失值与离群值处理:fillmissing与isoutlier的取舍

监测设备故障、节假日停更、传输丢失都会导致缺失值,空气质量数据几乎没有一份是完整无缺的。处理缺失值的第一个原则是:不要整行删除。六个监测因子各自有缺失,任何一列缺失就删掉整行,样本量可能直接从365掉到200,信息损失太大。

% 按列统计缺失数量 missingCount = sum(ismissing(data)); % 对浓度列做线性插值 concVars = {'SO2','NO2','CO','O3','PM2_5','PM10'}; for i = 1:length(concVars) col = concVars{i}; data.(col) = fillmissing(data.(col), 'linear'); end

fillmissing的'linear'方法用缺失点前后最近的有效值做线性过渡,适合污染物浓度这种连续渐变的时间序列,比用全局均值填充合理得多。如果某一天所有浓度列全部缺失,线性插值也救不回来,这种情况我建议把当天这一行删掉,因为多变量同时缺失时,插值等于在造数据。

离群值处理要更克制。空气质量里高浓度值本身可能就是污染事件,是建模要学习的重要信号,直接当离群值剔除等于把目标现象抹掉了。我会用isoutlier先看一遍分布,只处理那种明显超出物理可能的数值,比如负浓度或者超过1000的异常值,按当天信息修正或置为缺失再插值。

for i = 1:length(concVars) col = concVars{i}; outliers = isoutlier(data.(col), 'median'); data.(col)(outliers) = NaN; data.(col) = fillmissing(data.(col), 'linear'); end

这里用median方法做离群检测,对偏态分布更稳,均值方法容易被少数极端高值带偏。处理完之后再画一次数据分布,确认没有产生明显的阶梯断裂,这一步人工看一眼比任何指标都可靠。

3.4 特征工程与AQI等级标签生成

特征工程在空气质量分析里不算复杂,但有两个方向值得做。第一个是滞后特征:今天的AQI和昨天的浓度高度相关,把前一天的PM2.5、O3等浓度作为新特征加入模型,可以捕捉污染过程的连续性。

lagDays = 1; for i = 1:length(concVars) col = concVars{i}; lagCol = [col '_lag' num2str(lagDays)]; data.(lagCol) = [NaN; data.(col)(1:end-1)]; end

滞后特征加入后,数据头部会多出一行NaN,因为第一天没有前一天。这行要直接删掉,或者用fillmissing补齐——我建议直接删,免得引入没有任何物理意义的插值数据。滞后一天的合理性在于污染物浓度变化主要受气象和排放影响,一天之内的自相关本身很强,滞后太多天反而稀释有效信息。

第二个方向是构造标签。AQI等级映射通常按数值范围切分,在matlab里用discretize最直接:

aqiBins = [-Inf 50 100 150 200 300 Inf]; levelNames = {'优','良','轻度','中度','重度','严重'}; data.AQI_Level = discretize(data.AQI, aqiBins, 'categorical', levelNames);

注意discretize的区间默认是左开右闭,AQI等于50会归入“良”而不是“优”,这个边界细节在审查模型时经常被问起,要能说清楚。标签生成后,先用histogram看一遍等级分布,如果“严重”等级只有几条样本,说明类别严重不平衡,后面的模型评估指标必须格外小心,这个坑在第5章会专门展开。

提示:特征工程做完了先把data存成一份air_ready.mat,后续调参和换模型时直接load,不用每次从原始csv重复清洗一遍。事后这半小时的前期投入能省下很多试错时间。

4. 用fitctree实现决策树训练:最小跑通代码与必调参数

4.1 从训练集切分到混淆矩阵的最小跑通代码

数据准备好之后,写第一个能跑通的完整流程。这里有一个所有时间序列建模都必须遵守的原则:切分训练集和测试集时按时间顺序切,不要随机打乱。空气质量数据相邻日期的相似度非常高,随机切分会把同一时间段的数据同时放进训练集和测试集,验证精度看起来很高,落地到明天预测就翻车。

% 按时间顺序切分,前80%训练,后20%测试 nTrain = round(height(data) * 0.8); trainData = data(1:nTrain, :); testData = data(nTrain+1:end, :); % 取特征矩阵和标签,花括号取值得到数值矩阵 featNames = {'SO2','NO2','CO','O3','PM2_5','PM10'}; X_train = trainData{:, featNames}; Y_train = trainData.AQI_Level; X_test = testData{:, featNames}; Y_test = testData.AQI_Level; % 训练决策树分类器 tree = fitctree(X_train, Y_train, ... 'MaxNumSplits', 50, ... 'MinLeafSize', 5, ... 'SplitCriterion', 'gdi'); % 测试集预测并画混淆矩阵 Y_pred = predict(tree, X_test); figure; confusionchart(Y_test, Y_pred);

执行逻辑分四步:切分、取数、训练、评估。切分这里用序号索引而不是随机抽样的原因前面说过了,时间序切分是这套代码里最不能动的部分。花括号取数得到的是纯数值矩阵,而圆括号取出的是子表格,fitctree的输入必须是数值矩阵,这个细节初学者很容易卡住。fitctree的三个参数都做了显式指定,先按这个起步,下一节逐个解释怎么改。

跑完代码先看两个输出:命令行是否报错,以及混淆矩阵长什么样。混淆矩阵对角线越亮越好,但更重要的是看暗色格子集中在哪里——如果误判大多发生在相邻等级之间,比如“良”被错判成“优”,这是可以接受的误差方向;如果错到跳级,比如“轻度”直接被判成“严重”,说明特征或模型结构有问题,要回头检查数据。

4.2 四个必调参数:MaxNumSplits、MinLeafSize、SplitCriterion与Prune

fitctree有几十个可设置的参数,实战里大部分保持默认就行,真正影响结果的主要是下面四个。

参数名默认值作用常用区间
MaxNumSplitssize(X,1)-1限制整棵树的分裂次数上限,防止树过深20~100
MinLeafSize1每个叶子节点最少样本数,越大树越平滑1~20
SplitCriteriongdi分裂准则:gdi基尼 / deviance交叉熵 / twoing两类默认gdi
Pruneon是否做事后剪枝,减少过拟合枝条on

MaxNumSplits是防止过拟合的第一道闸门。默认值等于样本数减1,等于完全不设限,树会长到每个叶子只有一个样本。对几百条数据的小样本,50次分裂已经足够;数据量达到几千条,可以放宽到100。MinLeafSize和MaxNumSplits经常配合使用:叶子最少样本数从1提高到5,树自然变矮变粗,单棵树的方差下降。我在空气质量数据上的经验是MinLeafSize取5到10之间,效果最稳。

SplitCriterion的三个选项里,gdi和deviance在绝大多数数据集上结果几乎一致,没必要来回切换。twoing是专门为多分类设计的准则,当类别数量多且分布不均衡时偶尔会更好,但计算慢一些。对AQI六等级数据,默认gdi已经够用。Prune参数保持默认on即可,它做的事是树长完之后剪掉对验证精度没有帮助的枝条,实现的是CART算法的标准后剪枝逻辑。

参数之所以要逐个解释,是因为网格搜索时你会面对一个组合爆炸的问题:两个参数各取10个候选值,就是100个模型。知道每个参数控制的是“树多深”还是“叶子多密”,才不用盲目穷举,能先固定一个、调另一个,把搜索空间砍掉一半。

4.3 画树、看规则与predictorImportance特征重要度

模型训练完成只是第一步,决策树和黑匣子模型最大的不同在于,它可以把完整的决策逻辑画出来给人看。

% 图形化展示决策树 view(tree, 'mode', 'graph'); % 计算特征重要度并画条形图 imp = predictorImportance(tree); figure; bar(imp); set(gca, 'XTickLabel', {'SO2','NO2','CO','O3','PM2_5','PM10'});

view的graph模式会打开一个交互式窗口,每个节点显示分裂特征、阈值、类别分布和节点样本数,鼠标点上去还能展开子树。这是答辩和写报告时最有说服力的一张图。读懂这张图的关键是看浅层分裂:根节点和第一层子节点用的特征,就是整个数据集里区分能力最强的因子。比如根节点如果是“PM2_5 > 75”,说明PM2.5对AQI等级的判别贡献最大,这个结论可以直接写进分析报告。

predictorImportance返回的是一个向量,长度等于特征数,顺序和你喂给fitctree的X_train列顺序一致。条形图能直观看出哪个因子几乎不参与分裂,那种重要度接近0的特征,可以考虑从模型里去掉,简化后续部署。要注意的是,CART的特征重要度受分裂顺序影响,如果两个强相关特征存在,重要度会被摊薄分配到两个特征上,看相对大小没问题,别把具体数值当作严格的归因比例。

提示:如果view画出来的树太深、图形窗口里全是拥挤的小节点,说明MaxNumSplits和MinLeafSize还没约束到位。先回头调参,再回来看树,否则这棵树在报告里没法展示。

5. 决策树空气质量分析的5个翻车排坑记录:现象、原因与解法

5.1 类别不平衡导致模型“躺赢”:准确率虚高但重度污染全漏

现象:测试集准确率超过90%,表面前途一片光明,但翻看混淆矩阵发现“重度污染”和“严重污染”两行的预测结果全是0。模型把绝大部分样本都判成“良”或“轻度”,因为全年重污染天数本来就不足1%,哪怕把所有样本全部预测为“良”,准确率也能轻松过90%。

原因:决策树的生长过程倾向于让整体准确率最大化,对极少数类别的错误不敏感。空气质量的等级分布天然是金字塔形,优良天数占大头,污染天数稀少,类别不平衡是这个场景的必然属性。

解决:第一步,不要只看准确率,要算每个类别的召回率,也就是每一类真实样本里模型找回了多少。第二步,如果重污染样本数量实在太少,连训练都喂不饱,考虑用代价敏感学习,给少数类分配更高的误分类权重;或者在数据层面做重采样。matlab里代价矩阵和类别权重都直接影响分裂过程,但改之前要明白这不是免费的:提高重污染类别的权重,优良类别的误判大概率会变多,你得权衡业务上哪种误判代价更高。

C = confusionmat(Y_test, Y_pred); recall = diag(C) ./ sum(C, 2); precision = diag(C) ./ sum(C, 1)'; disp(table(unique(Y_test), recall, precision));

5.2 时间序列随机切分引发数据泄漏:验证精度高到不真实

现象:用cvpartition做随机交叉验证时精度冲到95%,感觉模型完美收敛。把同一套参数直接部署到“用上个月数据预测下个月”的场景时,精度立刻掉到70%以下,前后差距大到让人怀疑是不是代码写错了。

原因:空气质量是强时间相关数据,相邻两天的PM2.5、NO2浓度高度相似。随机交叉验证相当于把同一条污染过程的多数样本同时分给了训练集和验证集,模型在验证集上看到的不是新数据,而是训练样本的“近亲”。这叫数据泄漏,是时序建模最隐蔽的坑,随机森林和决策树都会中招。

解决:回到第4.1节的切分方式,按时间顺序头80%训练、后20%测试。交叉验证也要用带时间信息的方案,在matlab里可以用cvpartition(data.time, 'Holdout', 0.2)结合分组逻辑,保证验证集永远在训练集之后。更严格的做法是滚动验证:比如用前24个月训练、接下来1个月做验证,再整体往前平移一个月重复,最后看平均效果。

5.3 缺失值整行删除把样本量削掉一半

现象:原始数据明明有12个月365行,跑完清洗代码后只剩190行,模型训练出来叶子节点样本少得可怜,树形图里到处是样本数小于等于5的叶子。

原因:六个监测因子各自都有缺失,代码里如果用了any(ismissing(data), 2)这种“任何一列缺失就删整行”的逻辑,遇到多列不同日期的零星缺失,样本量会迅速缩水。

解决:按列处理缺失,优先用fillmissing做线性插值。判断依据是缺失列和时间位置的关系:孤立单点缺失用插值最稳;如果某列连续缺了一周以上,要么该列剔除,要么先用上游数据做趋势估算,别指望线性插值能跨过一周的空档。处理完再看每列缺失比例,超过30%的列干脆删掉,宁可少一个特征也不要引入大面积虚拟数据。缺失比例和插补方式要在报告里写明,环境数据分析的评审特别看重数据处理的可追溯性。

5.4 Matlab中文注释乱码:脚本能跑但没法维护

现象:下载的源码包里中文注释显示成一堆乱码,脚本本身能运行,但想改功能时根本看不懂原作者的意图。换到新版matlab或在线版打开,乱码可能变成更严重的“出错”,连脚本都开始报错。

原因:matlab在不同操作系统和版本上的默认编码不一致,老版本在中文Windows上常用GBK保存脚本,新版默认UTF-8,打开时按错误解码方式读取,中文注释就成了乱码。源码经验包里这个问题尤其常见,因为整理者很少注意编码统一。

解决:优先的根治方案是让源码里的解释性文字全用英文写,彻底规避编码问题。如果必须保留中文注释,用matlab编辑器里的另存为把文件转成UTF-8编码,再重新打开检查一遍。另一个办法是给脚本头部加一行固定的字符编码处理代码,但不同版本兼容性不好,我测试下来不如直接统一英文注释省心。注释的目的是让人看懂逻辑,用哪国语言不影响代码质量。

5.5 树长得太深:训练精度100%验证精度崩盘

现象:训练集上准确率100%,测试集上只有82%,树形图画出来有几十层深,左边分支和右边分支的深度非常不对称,叶子节点里大量样本数只有1或2。

原因:这是典型的决策树过拟合。MaxNumSplits不设限、MinLeafSize取默认1时,树会把训练集里很多噪声细节当作规律记下来,单条样本的偶然波动都长成了一个分支。训练精度必然100%,泛化精度就说不定了。

解决:只做一件事,立刻提升MinLeafSize。从5开始往上调,每调一次跑一遍测试集精度,你会发现测试精度先上升、到某个点后开始下降,那个拐点就是当前数据量下的最优叶子规模。结合第6章的网格搜索一次性找MaxNumSplits和MinLeafSize的组合,比手动从1逐个试到20高效得多。判断树是否过拟合还有个直观信号:交叉验证精度和测试集精度差超过5个百分点,大概率过拟合,差在3个百分点以内算正常波动。

6. 用交叉验证网格搜索代替手感调参:一次定位最优树结构

第4.2节讲参数时提到两个参数要配合搜索,这里给一个可以直接抄的网格搜索脚本。交叉验证改成用kfoldLoss评估,默认是10折,样本量不大时自动降为5折,正好覆盖气象类数据集的典型规模。

leafRange = [1 3 5 10 20]; splitRange = [10 20 50 100 200]; accMat = zeros(numel(leafRange), numel(splitRange)); for i = 1:numel(leafRange) for j = 1:numel(splitRange) mdl = fitctree(X_train, Y_train, ... 'MinLeafSize', leafRange(i), ... 'MaxNumSplits', splitRange(j), ... 'CrossVal', 'on'); accMat(i, j) = 1 - kfoldLoss(mdl); end end [bestRow, bestCol] = find(accMat == max(accMat(:))); bestLeaf = leafRange(bestRow); bestSplit = splitRange(bestCol); finalTree = fitctree(X_train, Y_train, ... 'MinLeafSize', bestLeaf, ... 'MaxNumSplits', bestSplit); Y_pred = predict(finalTree, X_test); confusionchart(Y_test, Y_pred);

网格搜索的逻辑是把两个参数的候选值排成二维矩阵,每个组合做一次交叉验证,取交叉验证精度最高的组合。注意这里用的是X_train而不是原始全量数据,交叉验证只发生在训练集内部,最后再拿测试集验证一次,保证评估链路不泄漏。25个组合在几百条数据上几秒钟就能跑完,任何换参数猜玄学的做法都更费时。

搜索完成后,把bestLeaf和bestSplit代入重训,再看一次混淆矩阵。我一般还会顺手做一道检查:最高精度是否出现在参数网格的边缘位置——如果bestLeaf取到20是网格最大值,说明边界外可能还有更好的选择,扩大网格重搜;如果最优值落在网格中间区域,说明这段区间覆盖合理,结果可信。另外注意一个容易被忽略的细节:交叉验证精度比测试集精度高很多是正常的,但反过来交叉验证精度明显低于测试集精度,说明数据切分可能出了问题,回去检查时间顺序。

这套流程走完,再把第4.3节那两行view和predictorImportance跑一遍,用最优参数重新画树和特征重要度图,最终报告里放的就是这套结果。我自己早期做树模型时也贪深,总觉得树长得越大信息越全,直到有一次交叉验证打回原形,才老老实实把网格搜索当成标配。现在的习惯是拿到任何数据先画直方图看类别分布,再切分、再搜参,宁可多花十分钟搜网格,也绝不再靠手感碰参数。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 1:04:07

GMM运动目标检测实战:RGB背景建模与OpenCV跟踪

简介:这份资源面向计算机视觉入门与进阶学习者,聚焦基于混合高斯模型(GMM)的运动目标检测与目标跟踪实现,适合需要理解背景建模、前景分离与多帧目标定位的读者参考。压缩包共2个文件,包含1个m脚本与1个txt…

作者头像 李华
网站建设 2026/9/24 1:00:23

Java Agent技术:从原理到生产实践全解析

1. 为什么Java开发者需要关注Agent技术?在Java生态中,Agent技术一直是个既神秘又强大的存在。记得我2016年第一次接触Java Agent时,花了整整两周才搞明白如何实现一个简单的类转换。如今在阿里云原生团队带架构师岗位,发现90%的P7…

作者头像 李华
网站建设 2026/9/24 1:00:03

GTA5 242个角色模组整合包:模型替换、骨骼兼容与性能调优指南

1. 从242个角色模组说起:这个整合包到底装了什么第一次看到“242个美女角色”这个数字,我的反应和大多数人一样——这怕不是把网上能搜到的角色模型全塞进一个压缩包就完事了。但实际拆开这个整合包之后,我发现事情没那么简单。242个角色不是…

作者头像 李华
网站建设 2026/9/24 0:58:55

FinalShell连接Ubuntu:SSH远程连接与大数据实验环境配置指南

1. 实验场景与整体思路拆解1.1 这个实验到底在解决什么问题做大数据和数据库实验,最大的痛点不是你写不出那几行SQL,也不是搞不懂Hadoop的MapReduce原理,而是环境根本起不来。我见过太多同学在实验报告里写着“实验结果正确”,实际…

作者头像 李华
网站建设 2026/9/24 0:52:49

SVM-KNN组合模型原理与MATLAB实战:从置信度筛选到PCA降维实现

简介:一套面向机器学习初学者的SVM-KNN组合模型MATLAB实现资料,系统阐述支持向量机与K近邻的协同分类思路,适用于小样本非线性分类、信用风险评估等场景。压缩包共4个文件,整体约1.28MB,主要由可直接运行的m脚本、实验…

作者头像 李华
网站建设 2026/9/24 0:44:43

C++与OpenCV实现光学相位测量技术:相移法与三频外差法

1. 光学相位测量技术概述在工业检测、三维形貌测量等领域,光学相位测量技术因其非接触、高精度的特性而广受青睐。其中,相移法结合格雷码和三频外差法是两种主流的绝对相位获取方案。本文将深入解析基于C和OpenCV实现的这两种算法的核心原理与工程实践。…

作者头像 李华