资讯动态

机器学习实战:基于XGBoost的AQI预测与特征工程全流程

发布时间:2026/9/7 3:18:24 来源:尧图企业网站定制
简介面向环保数据分析初学者及相关从业者的一份机器学习项目资料以空气质量指数AQI为对象从环境监测数据出发完整演示了数据分析与预测建模的流程包括数据清洗、缺失值与异常值处理、特征标准化、基于pandas的探索性数据分析以及多种可视化图表绘制。压缩包共33个文件大小约4.23MB内含1个CSV原始数据文件、2个Jupyter Notebook分析代码、24张反映分析过程与结果的PNG图表、2个HTML交互式地图页面和Markdown说明文档整体目录结构清晰便于对照学习。项目采用Python及scikit-learn等工具应用线性回归、随机森林等算法构建模型结合交叉验证进行参数调优并对比不同算法的预测性能同时利用matplotlib等库输出可视化结果通过散点图、相关系数图等形式展示变量关系帮助直观理解数据分布、特征关系与模型误差。目前已有196人学习/下载适合需要完整案例参考、快速上手AQI预测项目的读者也可作为课程设计或入门实践的辅助资料。 选择这个“机器学习-03-AQI分析与预测”项目来写主要是因为后台收到不少读者私信说前面两篇偏理论希望看到一个完整的、从数据到模型的实战案例。正好手头有整理好的空气质量数据集和一套完整的建模代码就借这篇博文把整个流程走一遍。先说明一下这个项目是我自己实际建模过程的重现代码和数据都会完整放出来你可以直接运行复现更适合刚学完机器学习基础、想动手做第一个完整项目的读者。1. 项目背景与数据认知1.1 预测任务的本质先想清楚一个问题AQI预测到底是一个什么类型的机器学习任务答案是典型的回归问题。我们手里有一批历史污染物浓度数据和对应的气象条件要预测的标签是AQI数值或者某一种污染物浓度。这种问题在环境监测领域非常常见也是很多高校机器学习课程的标准作业题。但作业归作业真把一个预测系统做成能用的东西要考虑的点就多了。我先说一下数据集的基本情况。这份数据采集自某个城市国控监测站点时间跨度差不多一年包含了PM2.5、PM10、SO2、NO2、O3、CO六项常规污染物的小时浓度值以及温度、湿度、气压、风速等气象参数。原始数据大概有一万条左右每条记录都带时间戳。文件格式是CSV处理起来很方便。1.2 数据特征的时间属性这里有个容易被新手忽略的关键点这组数据自带时间属性所以在处理时不能像处理普通表格数据那样随便打乱。空气污染物浓度有很强的时序依赖今天下午的臭氧浓度高往往意味着前一天中午的光化学反应已经开始了。如果不考虑时间结构直接随机切分训练集和测试集会造成数据泄露——同一个时间段的内容既出现在训练集又出现在测试集里模型评估结果会虚高真正上线部署时立刻现原形。我当时采用的策略是按时间顺序做切分前80%作为训练集后20%作为测试集。这样模拟的是“用过去预测未来”的真实场景评估结果才有参考价值。2. 数据探索与预处理细节2.1 缺失值处理与异常值识别先把数据读进来用Pandas快速看了一眼概况。原始数据中SO2和CO这两列存在少量缺失占比大概在5%以下原因是部分监测仪器在特定时段进行了校准维护。对于时序数据我们不能简单地把缺失行删掉因为时间序列的连续性很重要。我选择的方法是前向填充ffill用缺失时刻之前最近的一条有效值来补。这个方法对这个数据集是合理的因为污染物浓度在短时间内变化幅度有限前向填充不会引入太大的误差。不过要注意一点如果缺失区间太长比如超过12小时用它补出来的数据可信度就比较低这种情况建议直接删除这部分记录。异常值方面的处理我相对克制。AQI数据里有一些看起来“异常”的高浓度值比如某天某个站点PM2.5一度冲到400以上看起来像异常值但这在冬季污染过程中可能完全真实。如果一刀切用3σ法则把它们清掉等于把数据里最有信息量的极端污染事件给抹掉了模型学到的东西反而失真。2.2 相关性分析与特征选择预处理完成后我先做了特征选择。计算所有特征与AQI的Pearson相关系数排序后结果很有意思特征与AQI的相关系数初步判断PM2.50.92强相关核心特征PM100.87强相关核心特征湿度-0.43中等负相关保留温度-0.28弱负相关保留风速-0.31弱负相关保留SO20.56中等正相关保留CO0.48中等正相关保留从这个相关系数表格能看到两个信息。第一PM2.5和PM10是AQI的最主要贡献因子这符合我国《环境空气质量指数AQI技术规定》中分指数计算的基本逻辑。第二气象条件里湿度对AQI影响最大湿度高往往伴随静稳天气污染物不容易扩散这个在后面的特征工程里可以进一步利用。我把相关系数绝对值低于0.1的特征去掉保留了浓度和气象相关的核心字段总共8个特征进入模型。3. 建模过程与参数实验记录3.1 特征工程不只是把数据丢给模型很多人做机器学习项目拿到数据就直接标准化然后开始跑模型忽略了特征本身的信息价值。在这个AQI项目里我做了两组额外的特征工程对最终模型效果提升非常明显。第一是构造温度湿度交互特征。空气污染和气象条件不是简单线性关系湿度高但温度低时污染物累积效应更强这实际上是气象学里的“逆温层”现象。我新增了一个特征用温度乘以湿度的值来捕捉这种交互影响。第二是构造滞后特征把前1小时PM2.5浓度作为特征放入当前时刻的样本中。污染物浓度有很强的自相关性这体现的是大气扩散的物理惯性滞后特征能把这种惯性传递给模型。3.2 多模型对比与调参记录整个项目我测试了三个模型线性回归、随机森林、XGBoost。分别说一下实测表现和调参重点。线性回归是最基础的对比基线。从结果看训练集R2在0.81左右测试集掉到0.75有明显的欠拟合。AQI和污染物浓度之间的关系里包含了很多非线性因素线性模型的上限就在那里它适合作为基准线但不适合直接上线使用。随机森林的效果比线性回归好了一截。测试集R2能够稳定在0.87左右。我把随机森林的参数网格搜索范围设定为n_estimators从50到300max_depth从5到20min_samples_split从2到10。实测最优参数是n_estimators200max_depth12min_samples_split4。这里有个很实用的经验随机森林对参数不敏感你只要把n_estimators调到足够大200以上max_depth不要超过20避免过拟合其他参数用默认值就能拿到还不错的分数。XGBoost是最终采用的主力模型。经过五折交叉验证最优参数组合为params { learning_rate: 0.05, # 学习率调低以减轻过拟合 max_depth: 6, # 树深6-8之间比较安全 n_estimators: 800, # 树的数量配合早停机制使用 subsample: 0.8, # 每棵树的样本采样比例 colsample_bytree: 0.8, # 每棵树的特征采样比例 reg_alpha: 0.1, # L1正则防止特征过多导致过拟合 reg_lambda: 1.0 # L2正则默认值就可以 }这些参数不是一次性试出来的我调的路径是先定学习率0.05再配合早停找n_estimators的最优值在验证集上连续50轮不提升就停最后再微调max_depth和subsample。记住一个经验调参永远优先调对结果影响最大的那个参数也就是学习率不要一上来就动所有旋钮。3.3 训练集与测试集的切分逻辑我在前面已经提过这个项目的切分逻辑是严格按照时间顺序。但训练时还要考虑一个具体操作因为时间相关性存在如果你用随机打乱的K折交叉验证来调参会让模型看到“未来的信息”导致交叉验证的分数虚高。所以我做交叉验证时使用的是按时间顺序切分的TimeSeriesSplit而不是默认的KFold。别小看这个细节很多项目线上效果差不是模型不行而是数据切分的时候作弊了。训练的时候偷了懒最后测试的时候还是要还的。4. 模型评估与结果解读4.1 评估指标的选择回归任务的标准评估指标我这里用了三个R2决定系数、均方根误差RMSE以及平均绝对误差MAE。在空气质量预测场景里我最关注的是RMSE因为它对“大幅偏离真实值”的预测会给更重的惩罚AQI预测的灾难性错误往往就是预测值和真实值差距特别大的情况。最终模型的测试集表现如下模型R2测试集RMSE测试集MAE测试集线性回归0.7524.316.8随机森林0.8718.111.2XGBoost0.9115.29.4RMSE为15.2意味着平均而言模型预测的AQI与真实AQI相差15左右。对AQI这种0到500区间的指数来说15的误差基本可以满足日常参考需求。不过这里我要坦白一点RMSE在AQI比较低50以下和比较高300以上的两个区间表现是不均匀的这个在残差分析里能看得很清楚。4.2 残差分析与模型失效场景我画了预测误差随时间变化的残差图发现一个规律在重污染过程AQI大于200的上升期和下降期模型预测值系统性偏低特别是在污染快速累积的头几个小时预测值跟真实值能相差30到50个点。原因也好理解模型学到的更多是“稳态”条件下污染物浓度和气象要素的关系对突发性的污染积累过程响应偏慢这本质上是因为模型输入里没有包含污染源排放变化的实时信息。另外还注意到一个跨季节的问题模型对夏天的预测误差整体小于冬天。这提示我如果能拿到更长时间跨度的数据比如两年以上按季节训练多个子模型或者把季节编码作为一个特征喂进去效果应该能更好。这也是后续迭代的方向。5. 完整代码实现与数据可用性说明5.1 项目目录结构完整项目文件我整理了一下包含以下文件AQI_Prediction/ ├── data/ │ └── air_quality.csv # 原始数据 ├── notebooks/ │ └── EDA.ipynb # 探索性分析 ├── src/ │ ├── preprocess.py # 数据预处理 │ ├── train.py # 模型训练与评估 │ └── config.yaml # 配置文件 └── results/ ├── predictions.csv # 测试集预测结果 └── model_metrics.json # 模型指标记录5.2 核心代码逻辑模型的训练部分核心代码我用的是scikit-learn和xgboost两个库代码量不大核心逻辑就几行import pandas as pd from sklearn.model_selection import TimeSeriesSplit from sklearn.preprocessing import StandardScaler from xgboost import XGBRegressor from sklearn.metrics import r2_score, mean_squared_error # 读取数据并做预处理略 # ... # 按时间顺序切分前80%训练后20%测试 train_size int(len(df) * 0.8) train, test df.iloc[:train_size], df.iloc[train_size:] # 分离特征和标签 feature_cols [PM2.5, PM10, SO2, NO2, CO, 湿度, 温度, 交互特征, 前1小时PM2.5] target_col AQI X_train, y_train train[feature_cols], train[target_col] X_test, y_test test[feature_cols], test[target_col] # 标准化特征 scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test) # XGBoost模型 model XGBRegressor( learning_rate0.05, max_depth6, n_estimators800, subsample0.8, colsample_bytree0.8 ) model.fit(X_train_scaled, y_train) # 预测与评估 y_pred model.predict(X_test_scaled) test_r2 r2_score(y_test, y_pred) test_rmse mean_squared_error(y_test, y_pred, squaredFalse) print(fTest R2: {test_r2:.3f}, RMSE: {test_rmse:.2f})这段代码基本上可以直接运行前提是环境里装好了pandas、scikit-learn、xgboost这几个库。数据文件air_quality.csv是公开可获取的空气质量监测历史数据如果你需要实际执行可以从公开的环境监测数据平台下载。代码中训练和预测的全过程大约在30分钟内就能跑完不会让你等太长时间。6. 常见问题与排查技巧6.1 预测结果始终偏低或偏高模型预测的AQI整体系统性偏差最常见的原因有两个。第一是数据标准化时用了错误的scaler在训练集上fit后忘了在测试集上transform直接对测试集重新fit了。这是sklearn使用中最高频的错误度量衡都变了预测结果自然歪掉。第二个原因是目标变量没做处理AQI数值分布在低值区域非常密集中高值很稀疏模型天然偏向学习出现频率高的样本区间所以你可以尝试对目标变量取对数让分布更均匀。6.2 交叉验证分数很高但测试集一塌糊涂如果训练集和验证集效果都好测试集立刻翻车九成是时间泄露问题。我在3.3节已经强调过一定要用时间顺序切分的TimeSeriesSplit同时特征工程里不能使用未来信息。比如有些人不小心用整段数据的均值和标准差去做标准化这等于让训练过程偷看了测试集的统计信息在真实场景中这种数据时不可能预先得到的。6.3 模型训练速度慢到无法忍受如果数据量上来了比如多站点多年小时级数据超过几十万条用默认参数的XGBoost会跑得非常痛苦。实际处理时可以采用hist作为tree_method这种分箱加速算法在sklearn的GBDT里叫histogram-based gradient boosting在XGBoost里就是hist训练速度可以快5到8倍精度损失非常小。如果仍然慢建议先用10%的数据做一次冒烟测试确认流程没问题再全量训练。注意当你刚开始跑通整个人工智能项目流程之后想深入做AQI预测这个方向很大概率会遇到“未知城市、未知时间段的预测”问题。本质上这种跨域预测在环境科学领域是公认难题。我的建议是优先收集目标城市至少一年以上的监测数据再训练不要指望用一个城市的模型直接迁移到另一个城市。7. 改进方向与个人心得7.1 从单站点到区域预测的扩展思路现在这个项目只用了单个站点的数据做预测实际业务中一个城市里有十几个国控站点如果把站点ID作为类别特征、把站点经纬度也加进去一起建模预测的对象就可以从“这一个站点未来几小时AQI”变成“整个城市未来几小时AQI空间分布”。这个扩展思路在环境监测平台、智慧城市建设中很有价值。从方法角度看空间相关性建模可以尝试图神经网络不过现阶段不是必须的。先用最简单的one-hot编码加线性模型把多站点扩展起来你就已经能做出远远超过演示水平的成果了图神经网络那些重武器留到业务确实有需要的时候再上不要为了炫技而过度设计。7.2 踩坑后的几个重要收获这个项目做完有几个实操层面的心得体会值得单独拎出来讲。第一特征工程的作用被很多人低估。最终模型从随机森林的0.87到XGBoost的0.91这4个百分点的提升里至少有一半功劳来自新构造的滞后特征和温湿度交互特征而不是模型换成了XGBoost。你去调模型参数、换模型架构不如先仔细审视一下特征里是否真的包括了物理世界的关键信息。污染物有物理惯性、有积累效应模型不会自己学到这些你要想办法把规律喂给它。第二不要只盯着R2和RMSE把预测误差按AQI等级分段统计分析。我后来把这个项目的结果做了一次拆分评估发现在空气质量等级“优”AQI 0到50时模型表现很好但“轻度污染”到“中度污染”这一段的误差最大。原因也很简单这个区间正好是累积过程的中间态大气物理化学反应最复杂边界特征不清晰。如果你能把“分段误差”当作默认评估方式来看待问题你对模型能力的认知会准确非常多而不是只看到一个漂亮的总分就觉得万事大吉。第三环境监测数据一旦碰上雨雪天气仪表读数会受影响这些记录在原始数据里看起来很异常但它们不是设备故障而是真实的自然现象。处理这些数据时一定要结合气象记录一起判断再决定去留别一看到异常值就从数据里把它们删掉。真实业务里保守处理异常值比激进清洗要可靠得多。这个项目做完我个人的体会是AQI预测这类环境数据挖掘问题技术门槛并不高难的是把气象知识、污染物化机理和数据建模真正融合到同一个框架里思考。后续如果有时间我打算用这个数据继续做一个多步预测把未来24小时逐小时的AQI变化趋势预测出来那会更贴近预警产品的真实需求。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价