新闻详情

新闻详情

首页 / 资讯中心 / 详情

MATLAB决策树实现空气质量分析:从数据预处理到模型调优

发布时间:2026/9/14 2:22:29来源:尧图网络
MATLAB决策树实现空气质量分析:从数据预处理到模型调优
简介面向环境监测、毕业设计及数据挖掘初学者的 MATLAB 决策树空气质量分析源码包聚焦 AQI 类别预测与数据可视化解决了从数据预处理到模型训练、结果展示的一整套流程。压缩包共150个文件容量约14.21MB以58个m脚本或函数为核心辅以14个mat数据文件、4个fig界面图、51张jpg结果图、5个xlsx表格以及docx/xls/pdf等文档覆盖源码、数据、界面和论文资料。目前已有51人学习下载具备一定参考价值。资源内不仅包含基于ClassificationTree等函数的决策树分类实现还提供ROC曲线、PR曲线、界面展示及小论文/毕设论文草稿覆盖数据预处理、特征选择、模型训练与评估等环节便于直接复现实验、理解算法细节并支撑课题撰写。整体目录结构清晰适合作为课程设计、环境数据分析或算法对比研究的起点。1. 把“空气质量分析”做成可解释的决策树项目从数据到模型用决策树做空气质量分析很多人第一反应是“这模型能刷多高的准确率”。实际跑过一轮就会发现决策树的优势从来不在精度上限而在它把“预测”变成了“规则”——当PM2.5超过某个阈值且湿度偏低时AQI等级大概率超标。这套规则可以直接拿去写报告、做预案、给非技术同事解释。标题里的“matlab基于决策树的空气质量分析源码”本质是三个环节的组装怎么组织气象和污染物数据、怎么调出可靠的分支结构、怎么用验证和重要性排序让结果站得住脚。适合刚接触机器学习又不想绕进深度学习框架的人无论是课程设计还是小规模业务探索这套路径都最省时间。2. 构建空气质量数据集把气象和污染物字段整理成决策树能吃的形态2.1 数据表结构和特征选择空气质量分析里目标变量无非两种形态AQI等级优、良、轻度污染、中度污染、重度污染和AQI数值。决策树分类挂在等级上决策树回归挂在数值上。无论哪一种喂给树模型的字段组成基本一致区别只在最后几列标签怎么写。常见的做法是先确定一张宽表每一行是一次监测记录列分为污染物浓度、气象条件、标签三类。决策树对量纲不敏感不会因为风速数值从0到10而压强污染物几千的数值所以不需要标准化。但字段语义要干净同一列不能混入两种不同监测口径的数据。字段名类型在模型中的作用PM2_5污染物浓度主要分裂特征颗粒物污染的直接指标PM10污染物浓度与PM2.5协同判断沙尘、扬尘场景CO污染物浓度燃烧源排放指示NO2污染物浓度交通源排放指示O3污染物浓度光化学反应和夏季污染指示temp气象连续量温度影响反应速率和排放习惯humidity气象连续量影响气溶胶吸湿增长和扩散wind气象连续量水平扩散清除能力pressure气象连续量表征静稳天气背景AQI_Level标签分类优/良/轻度/中度/重度AQI_Value标签回归连续数值单位无有一点值得注意O3和PM2.5在部分城市呈负相关白天O3高、PM2.5低夜里反过来。树模型会自动处理这种非线性关系不需要你手工构造交互项但前提是你把两个字段都留在特征表里。只留“常规六项”而砍掉O3会损失午后高臭氧污染这类判别能力。2.2 读入数据与缺失值处理拿到压缩包里的源码后第一步不是跑模型而是确认数据编排方式。CSV或Excel读入后先做缺失值检查再决定是删行、补均值还是插值。空气质量数据最怕的是把监测设备停机导致的“无记录”误当成低浓度。% 读取CSV假设列名与上面的字段表一致 data readtable(air_quality.csv); % 确定特征列和目标列 featureVars {PM2_5,PM10,CO,NO2,O3,temp,humidity,wind,pressure}; targetVar AQI_Level; % 分类标签优/良/轻度/中度/重度 % 只保留所有字段都完整的行 idxComplete all(~ismissing(data(:, [featureVars, targetVar])), 2); cleanData data(idxComplete, :); % 特征矩阵转为 double 数组 X cleanData{:, featureVars}; Y categorical(cleanData.(targetVar)); % 固定随机种子保证后序划分结果可复现 rng(42);缺失处理这里我一般不用fillmissing插值。原因很简单空气质量数据的缺失往往集中在某个站点的停机时段插值会把“没测到”伪装成“低浓度”树模型学到的阈值就会偏向这个假信号。样本量足够时删行最干净如果删完太少退而求其次用fillmissing(X, linear)按时间顺序插值并给插值过的样本打一个“质量标记”列让树模型自己决定是否信任这些样本。2.3 训练/测试划分的常见误区很多人在这一步直接用randperm随机打乱或者用cvpartition(Y, Holdout, 0.2)但不分层。空气质量标签天然不平衡优和良占比高中度和重度可能只有百分之几。随机划分可能把重度污染样本全留在训练集里测试集里一个都看不到。% 分层划分训练集和测试集中的类别比例保持一致 cvp cvpartition(Y, Holdout, 0.2); trainIdx training(cvp); testIdx test(cvp); XTrain X(trainIdx, :); YTrain Y(trainIdx); XTest X(testIdx, :); YTest Y(testIdx); % 输出比例检查 countcats(YTest) ./ numel(YTest) countcats(YTrain) ./ numel(YTrain)最后两行是必须做的自查。如果测试集中重度污染占比明显低于训练集说明分层没有生效检查Y是不是 categorical 类型。另一个常见误区是先用整个数据集做特征选择再划分训练测试——这会把测试集信息泄漏进特征选择过程导致交叉验证损失虚低。先划分、再在训练集上做任何特征筛选顺序不能乱。提示如果你的数据是按日期排列的监测序列并且建模目标是预测未来几天的空气质量应该按时间切分而不是随机切分。决策树不是时序模型但如果用未来数据预测过去指标再好看也没有业务意义。3. 用 fitctree / fitrtree 训练决策树模型参数与调优路径3.1 分类还是回归目标变量怎么选同样一组特征既可以用fitctree做分类也可以用fitrtree做决策树回归。分类输出的是等级适合写“超标预警”回归输出连续值适合计算“今明两天AQI差值”。我通常两套都跑先用分类树看规则是否清晰再用回归树看数值误差。% 分类树预测AQI等级 mdlClass fitctree(XTrain, YTrain, ... MaxNumSplits, 20, ... MinLeafSize, 5); % 回归树预测AQI数值标签换成连续向量 AQIValueTrain cleanData.AQI_Value(trainIdx); mdlReg fitrtree(XTrain, AQIValueTrain, ... MaxNumSplits, 20, ... MinLeafSize, 5);分类树返回的Mdl是一个ClassificationTree对象里面带有CutPoint、CutPredictor、NodeSize等属性可以在工作区展开看每个节点的分裂信息。回归树则是RegressionTree叶子节点存储的是该区域样本的均值。实际项目里我会先用默认参数训练一版直接打印view(mdlClass)看树长什么样。如果树太深、节点太多就限制MaxNumSplits如果叶子样本太少、预测结果抖动就调大MinLeafSize。这一步的目标不是一次到位而是建立“参数变化→树结构变化→损失变化”的感觉。3.2 MaxNumSplits、MinLeafSize、MinParentSize 怎么协同决策树生长可以理解为每次分裂挑一个特征、选一个阈值使分裂后两个子节点的不纯度之和最小。这个过程的终点由三个参数共同控制只看其中一个很容易踩坑。参数默认值作用建议范围MaxNumSplitsn-1限制树的最大分支数直接控制树的规模小样本从 520 开始试MinLeafSize1叶子节点最少样本数增大可防过拟合分类 520回归 310MinParentSize10内部节点最少样本数必须不小于 MinLeafSize设为 MinLeafSize 的 2 倍附近SplitCriteriongdi分类默认基尼指数回归默认 MSE保持默认即可Pruneon完成后是否保留剪枝序列保持 on剪枝与否靠交叉验证决定这三个参数不是独立生效的。树每分裂一次要同时满足“当前节点样本数 ≥ MinParentSize”和“分裂后子节点样本数 ≥ MinLeafSize”并且总分裂次数不能超过 MaxNumSplits。多数教程只调MaxNumSplits结果发现验证曲线一直抖动原因是MinLeafSize1时每个叶子都只有一个样本验证集上一旦归类错误单个样本就把误差拉得很高。我的一般做法是先固定MinLeafSize5让MaxNumSplits从 5 到 30 扫一遍找到合适的树深度后再把MinLeafSize从 3 到 15 扫一遍看交叉验证损失是否还能下降。两步走不要同时扫三个参数否则组合爆炸且难以定位过拟合来源。3.3 交叉验证与过度拟合的观察方法调参时最值得信任的指标不是测试集准确率而是 K 折交叉验证损失。因为测试集只能用来评估最终模型不能反复看着它调参否则测试集也变成了训练集的一部分。% 对 MaxNumSplits 从 3 到 30 扫描观察训练损失与 5 折验证误差 rng(42); splitValues 3:2:30; trainLoss zeros(size(splitValues)); cvLossValues zeros(size(splitValues)); for i 1:numel(splitValues) mdlCV fitctree(XTrain, YTrain, ... MaxNumSplits, splitValues(i), ... MinLeafSize, 5, ... CrossVal, on, KFold, 5); trainLoss(i) resubLoss(mdlCV.Trained{1}); cvLossValues(i) kfoldLoss(mdlCV); end % 绘图观察训练误差与交叉验证误差的分离点 figure; plot(splitValues, trainLoss, o-, splitValues, cvLossValues, s-); legend(训练集重代入损失, 5折交叉验证损失);CrossVal设为 on 时fitctree返回的是ClassificationPartitionedModel它的Trained{1}是第一折子模型。resubLoss(mdlCV.Trained{1})算的是该子模型在训练数据上的重代入误差注意这里不是全量训练集而是该折的子训练集。kfoldLoss(mdlCV)则把五折的预测结果合并给出平均泛化误差。观察规则当两条曲线都下降时增大分裂数合算当训练损失继续下降而验证损失开始回升或持平说明模型开始记忆训练样本的噪声过拟合已经出现。取回升前的分裂数即可。扫描时固定KFold5和随机种子否则每一轮验证集划分不同曲线不可比。4. 验证、剪枝与变量重要性让决策树结果可信4.1 K 折交叉验证输出与混淆矩阵选定参数后用全量训练集重新训练一次拿到测试集的混淆矩阵。这一步是给别人看效果的关键输出。% 用调好的参数训练最终分类树 finalMdl fitctree(XTrain, YTrain, ... MaxNumSplits, 11, ... MinLeafSize, 5); % 测试集预测 YPred predict(finalMdl, XTest); % 混淆矩阵行是真实类别列是预测类别 [C, order] confusionmat(YTest, YPred); disp(C); disp(order);混淆矩阵的输出中对角线是预测正确的样本数。对空气质量分析而言更值得关注的是非对角线的“相邻误判”和“跨级误判”。把轻度污染误判成良和把重度污染误判成轻度业务含义完全不同。前者只是预警偏差后者意味着没能触发应急响应。我一般会额外算一列“按真实类别的召回率”用C ./ sum(C, 2)得到每行的比例一眼看出哪个类别最容易漏。4.2 剪枝与代价复杂度权衡fitctree默认开启剪枝序列也就是说训练完成后模型内部保存了从满树到单节点树的一整条剪枝路径。可以用cvloss找出交叉验证误差最小的剪枝级别。% 查看剪枝级别中验证误差最小的那一级 [~, ~, ~, bestLevel] cvloss(finalMdl, Subtrees, all, KFold, 5); disp(bestLevel); % 按该级别剪枝并可视化 prunedMdl prune(finalMdl, Level, bestLevel); view(prunedMdl, Mode, graph);cvloss返回的第一个参数是各剪枝级别的误差第四个数是最优剪枝级别。prune(finalMdl, Level, bestLevel)返回一个新模型比原模型更小、验证误差更低。view(..., Mode, graph)会弹出一个交互式树视图每个节点上标着分裂特征、阈值和样本量这是给业务方解释模型最快的方式。剪枝级别不是越大越好。剪过头会把树变成只有根节点的“一根桩”所有分裂信息全部丢失虽然交叉验证误差可能很低但模型变成纯比例预测没有分析价值。正确的做法是看cvloss返回的误差曲线在误差上升不超过一个标准误的前提下尽量选小树也就是“在简约和准确之间取平衡”。4.3 变量重要性排序与随机森林对照决策树的可解释性不只是画图还包括回答“哪个因素对污染等级贡献最大”。predictorImportance给出每个特征在整棵树中贡献的不纯度下降总量其数值可以看作所有特征相对重要性的占比。% 计算变量重要性并按从大到小排列 imp predictorImportance(finalMdl); [sortedImp, idx] sort(imp, descend); for i 1:numel(featureVars) fprintf(%s: %.4f\n, featureVars{idx(i)}, sortedImp(i)); end变量重要性在空气质量分析里通常会得到一个直观结论PM2.5 和湿度排在最前风速和气压紧随其后。如果 PM10 排到第一而 PM2.5 很低说明数据集里可能有沙尘事件颗粒物粒径谱和常规污染不同需要从业务角度复核数据质量。单棵决策树的方差较大换一批训练数据树的结构可能完全不同重要性排序也会波动。所以我通常用随机森林做一次对照树的数量设为 100其他参数和单棵树保持一致再输出其OOBPermutedPredictorDeltaError排序。% 随机森林对照限制单棵树深度与之前的单棵树一致 rng(42); bagMdl TreeBagger(100, XTrain, YTrain, ... Method, classification, ... MaxNumSplits, 11, ... MinLeafSize, 5, ... OOBPrediction, on); % 袋外预测误差随树数量变化 figure; plot(oobError(bagMdl)); xlabel(树的数量); ylabel(袋外分类误差);决策树和随机森林的取舍就在这一步体现随机森林通过集成降低方差、提升精度但代价是失去单棵树的清晰规则单棵决策树精度稍低但每一条分裂规则都能追溯到具体污染物浓度阈值。对照结果如果两者精度接近说明数据中的信号非常强适合直接用单棵树交付如果随机森林明显占优说明单棵树的方差太大最终交付时可以考虑输出一棵剪枝树作为解释工具用森林做预测两者互补。提示TreeBagger 的输入输出语法和 fitctree 不完全一致尤其注意 categorical 标签在不同 MATLAB 版本中的兼容性。如果报标签类型错误把 Y 转为 cellstr 再传入。5. 落地技巧用参数网格扫描一次跑完决策树的调参和出图调参最耗时间的不是训练而是反复在脚本和工作区之间切换。我习惯把参数扫描写成一个紧凑循环一次性跑完 Splits 和 LeafSize 的组合输出每组验证误差顺带把最优模型的变量重要性和部分依赖图都生成好。% 紧凑网格扫描MaxNumSplits × MinLeafSize splitGrid [6 8 11]; leafGrid [3 5 8]; bestLoss Inf; bestParams []; for s splitGrid for l leafGrid mdl fitctree(XTrain, YTrain, ... MaxNumSplits, s, MinLeafSize, l, ... CrossVal, on, KFold, 5); loss kfoldLoss(mdl); fprintf(splits%d leaf%d - loss%.4f\n, s, l, loss); if loss bestLoss bestLoss loss; bestParams [s, l]; end end end % 用最优参数训练最终模型 bestMdl fitctree(XTrain, YTrain, ... MaxNumSplits, bestParams(1), ... MinLeafSize, bestParams(2));这组网格只有 9 个组合训练开销几乎可以忽略。网格扫描后不要直接取验证损失最低的那一组因为小数据集上 K 折误差有噪声某个组合可能恰好撞上低值。我会再看一眼相邻组合的损失值如果相差不到 0.005就选树更小、叶子更大的那一组保证泛化稳定性。这个“宁可损失一点精度、也要更简单的规则”的选择逻辑在决策树项目里尤其重要。训练完成后出图的顺序也固定下来view看树结构predictorImportance看特征贡献最后加一个plotPartialDependence看两个主要特征的联合效应。部分依赖图对空气质量分析特别有用比如看 PM2.5 和湿度如何共同驱动污染等级上升这比单变量柱状图更容易解释给非技术背景的人。figure; plotPartialDependence(bestMdl, {PM2_5, humidity}, 1);这条命令会在观测点 1 处计算两个特征的联合预测效果展示出“固定其他特征时PM2.5 和湿度在什么取值下预测等级最高”。如果图上出现明显的阶梯跳跃说明树模型在该区域发生了关键分裂这个跳点对应的 PM2.5 浓度就是值得写进报告的分级阈值。如果数据集有几十万行先把样本抽到 5 万以内做第一轮网格扫描等树结构稳定后再用全量数据重训练决策树的分裂点在小样本上已经能复现全量数据只是把叶子里的样本数变大。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

PHP依赖供应链安全:挑战与防护实践 2026/9/14 4:04:37

PHP依赖供应链安全:挑战与防护实践

1. PHP依赖供应链安全现状与挑战PHP作为全球使用最广泛的服务器端脚本语言之一,其生态系统包含超过30万个Composer包,平均每个PHP项目依赖89个第三方包(数据来源:Packagist 2023年度报告)。这种高度依赖第三方组件的开…

阅读更多 →
量子通信协议DREAMVFIA:工程化实现与性能优化 2026/9/14 4:04:37

量子通信协议DREAMVFIA:工程化实现与性能优化

1. 项目背景与核心价值量子纠缠通信协议DREAMVFIA的开源发布标志着量子通信技术从实验室走向工程化的重要一步。这个项目首次将量子纠缠的理论特性与经典通信协议设计原则深度融合,构建了一套可实际部署的混合通信框架。我在量子通信领域工作八年,见证过…

阅读更多 →
构建全生命周期数据安全防护体系的关键技术与实践 2026/9/14 4:04:37

构建全生命周期数据安全防护体系的关键技术与实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
pwn入门必读:栈溢出原理与内存布局实战详解 2026/9/14 4:04:37

pwn入门必读:栈溢出原理与内存布局实战详解

先给各位对二进制安全感兴趣的朋友交个底:这篇文章我要讲的是pwn方向绕不开的第一座山——”栈“和”内存“。不管你是刚看完几篇pwn入门文章、正准备在buuctf上刷第一道题,还是已经能跑通ret2text但一遇到ret2libc就发懵,这篇文章都适合你。…

阅读更多 →
移动App漏洞分析实战:从信息收集到漏洞挖掘的完整指南 2026/9/14 4:04:37

移动App漏洞分析实战:从信息收集到漏洞挖掘的完整指南

别把漏洞分析想得太玄乎。我做移动端安全评估这几年,最深的感触就是:大部分App不是被什么天顶星技术打穿的,而是倒在最基础的几个洞上——越权、明文存储、传输层裸奔、WebView乱开。漏洞分析说白了,就是站在攻击者视角&#xff0…

阅读更多 →
存量 OpenWork 部署如何安全完成 Gateway 数据库迁移与镜像升级? 2026/9/14 4:01:37

存量 OpenWork 部署如何安全完成 Gateway 数据库迁移与镜像升级?

存量 OpenWork 部署如何安全完成 Gateway 数据库迁移与镜像升级? 【免费下载链接】openwork The open-source alternative to Claude Cowork (powered by opencode) 项目地址: https://gitcode.com/GitHub_Trending/ope/openwork 如果你已经运行着一套 Den/M…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞