1. 空气质量数据项目为什么值得做空气质量指数AQI这个东西表面上看就是每天手机天气里一个带颜色的数字但真要把它的来龙去脉摸清楚你会发现它背后牵扯的东西远比想象中复杂。我从几年前开始接触环境数据分析前前后后做过好几个跟AQI相关的项目有的是帮朋友做课题有的是自己拿来练手踩过的坑不算少。今天就把这套“AQI分析与预测”的完整思路拆开来讲从数据获取、清洗、特征工程到可视化分析、模型训练、结果解读尽量把每个环节的为什么和怎么做都说透。这篇文章适合谁看如果你已经会一点Python基础语法知道pandas和matplotlib大概怎么用但还没完整做过一个数据分析项目那这篇就是写给你的。如果你已经做过一些项目但每次都是拿到数据直接fit不知道特征该怎么构造、模型结果该怎么解释那这篇也能帮你补上中间缺失的那一环。AQI预测这个场景的好处在于它既有明确的实际意义又有足够的数据量和特征维度让你折腾而且结果好坏很容易验证不像有些项目做完自己都不知道对不对。先说清楚一件事AQI预测不是那种“预测明天股票涨跌”的玄学问题。它的底层逻辑是污染物浓度变化而污染物浓度受气象条件、季节规律、人类活动周期等多重因素影响这些因素大部分是可观测、可量化的。所以只要特征选得对、模型用得合理做到“大致准确”是完全可行的。但如果你指望用几行代码就做到误差极小的精确预测那也不现实原因后面会详细说。2. 数据获取与理解AQI到底是怎么算出来的2.1 AQI的计算逻辑与六项污染物很多人拿到AQI数据就直接开始建模连AQI是怎么来的都不清楚这是第一个大坑。AQI不是一个原始测量值它是根据六项污染物浓度折算出来的综合指数。这六项分别是PM2.5、PM10、二氧化硫、二氧化氮、一氧化碳、臭氧。每一项污染物都有自己的浓度限值标准根据实测浓度和限值的关系先算出各项的IAQI个体空气质量指数然后取六项中的最大值作为当天的AQI。这个逻辑非常关键因为它决定了你后面做特征工程时的思路。AQI的本质是“最差的那项污染物决定了整体空气质量”所以如果你要预测AQI光看历史AQI序列是不够的必须把六项污染物的浓度也纳入进来。我见过有人只拿AQI一列数据做时间序列预测结果模型学到的只是滞后关系一旦遇到污染物结构变化就完全失效。提示如果你拿到的数据集只有AQI一列建议先去找包含六项污染物浓度的完整数据。很多公开数据平台都提供分项浓度数据不要偷懒。2.2 数据字段的常见构成与含义一份典型的空气质量数据集通常包含以下字段日期时间、城市名称、AQI数值、空气质量等级优、良、轻度污染等、PM2.5浓度、PM10浓度、二氧化硫浓度、二氧化氮浓度、一氧化碳浓度、臭氧浓度。有些数据集还会附带气象数据比如温度、湿度、风速、风向、气压、降水量。这里要特别注意单位问题。PM2.5和PM10的单位通常是微克每立方米一氧化碳是毫克每立方米臭氧有时是微克每立方米有时是毫克每立方米。不同来源的数据单位可能不一致合并之前一定要统一。我曾经把两个不同来源的数据直接concat结果一氧化碳那一列数值差了1000倍模型跑出来的特征重要性完全乱套排查了大半天才发现是单位问题。2.3 数据质量检查的必做动作拿到数据后先别急着画图按顺序做这几件事检查缺失值比例按列统计看看哪些字段缺失严重检查时间连续性确认有没有整天缺失的情况检查数值范围看看有没有明显异常的极值检查重复记录特别是按城市和时间维度去重检查数据类型确保数值列没有被读成字符串我一般会写一个简单的检查函数一次性输出这些信息。这样做的好处是你对数据的整体状况心里有数后面做任何处理都有依据而不是凭感觉。3. 数据清洗与特征工程决定模型上限的关键步骤3.1 缺失值处理的策略选择缺失值处理没有万能方案要看缺失的比例和缺失的机制。如果某一列缺失超过40%我通常会考虑直接丢弃这一列因为填充引入的噪声可能比信息还多。如果缺失在5%到40%之间可以用插值法填充时间序列数据优先用线性插值或前向填充。如果缺失低于5%用均值或中位数填充问题不大。但这里有个细节AQI数据的时间连续性很强相邻几小时的数值通常变化不大所以线性插值的效果一般比均值填充好。我实测过对于小时级数据线性插值填充后的模型效果比均值填充高出大概3到5个百分点这个差距在精细预测场景下还是很明显的。还有一种情况是整段时间缺失比如某几天完全没有数据。这种就不要硬填了直接在时间序列上标记为缺口建模时把这段时间排除掉。硬填出来的数据会让模型学到虚假的规律。3.2 时间特征的构造方法时间特征是AQI预测里最重要的一类特征没有之一。因为空气质量的变化有极强的周期性和季节性。我通常会构造以下几类时间特征小时特征0到23的整数值反映一天内的变化规律星期特征0到6区分工作日和周末月份特征1到12反映季节变化是否周末二值特征是否节假日二值特征需要额外维护一个节假日列表季节标签春、夏、秋、冬但直接把这些整数丢给模型有个问题模型会认为23点和0点差距很大但实际上它们是相邻的。所以对于小时和月份这种周期性特征更好的做法是做三角函数编码。具体来说就是用sin和cos两个值来表示一个周期位置这样23点和0点在数值空间里就是接近的。import numpy as np import pandas as pd def add_cyclical_features(df, col, period): df[col _sin] np.sin(2 * np.pi * df[col] / period) df[col _cos] np.cos(2 * np.pi * df[col] / period) return df df add_cyclical_features(df, hour, 24) df add_cyclical_features(df, month, 12)这段代码看起来简单但效果提升很明显。我在一个城市级AQI预测任务上对比过加了周期编码之后均方根误差下降了大约8%。3.3 滞后特征与滑动窗口统计AQI预测本质上是一个时间序列问题所以历史信息非常重要。滞后特征就是把前几个时间点的AQI值作为当前时刻的输入特征。比如用前1小时、前2小时、前3小时、前24小时的AQI来预测当前AQI。滞后阶数怎么选我的经验是对于小时级数据至少取到前24小时因为日周期很明显如果数据量允许取到前48小时或72小时更好。但也不是越多越好滞后阶数太多会导致特征维度爆炸而且远期滞后特征的信息量很低反而增加过拟合风险。除了滞后特征滑动窗口统计也很有用。比如过去6小时AQI的均值、标准差、最大值、最小值。这些统计量能反映近期的污染趋势和波动程度比单点滞后值更稳定。for lag in [1, 2, 3, 6, 12, 24]: df[faqi_lag_{lag}] df[AQI].shift(lag) for window in [6, 12, 24]: df[faqi_roll_mean_{window}] df[AQI].shift(1).rolling(window).mean() df[faqi_roll_std_{window}] df[AQI].shift(1).rolling(window).std()注意这里用了shift(1)目的是避免数据泄漏。滑动窗口统计必须基于当前时刻之前的数据不能把当前时刻的值也算进去否则模型在训练集上表现很好一到测试集就崩了。3.4 气象特征的引入与处理如果数据集中包含气象数据一定要用起来。风速、湿度、温度、气压这些因素对污染物扩散和生成有直接影响。比如风速越大污染物越容易扩散AQI通常越低湿度高的时候颗粒物容易吸湿增长PM2.5浓度可能上升。气象特征的处理相对直接数值型特征做标准化就行。但风向这个特征比较特殊它是角度值0度和360度是同一个方向直接当数值用会有问题。处理方法和小时特征类似做sin和cos编码。注意气象数据的缺失率通常比AQI数据高如果某个气象字段缺失严重不要强行填充可以考虑只用缺失较少的几个气象特征。4. 探索性数据分析先看懂再动手4.1 时间维度上的分布规律做任何预测任务之前先画图。AQI数据至少要看这几张图按小时的均值变化曲线、按月份的均值变化曲线、按星期的均值变化曲线。这三张图能告诉你数据的基本周期结构。从我做过的情况来看AQI通常呈现明显的“双峰”或“单峰”日变化模式。冬季往往是全年AQI最高的季节夏季相对较低。周末和工作日的差异因城市而异有些城市周末AQI明显低于工作日有些则差别不大。这些规律不是绝对的但大方向不会错。画图的时候建议用箱线图而不是简单的折线图因为箱线图能同时展示中位数、四分位数和异常值信息量更大。特别是AQI这种波动较大的数据只看均值曲线会丢失很多信息。4.2 污染物之间的相关性分析六项污染物之间不是独立的它们之间存在复杂的相关性。比如PM2.5和PM10通常高度正相关因为PM2.5本身就是PM10的一部分。二氧化氮和臭氧在某些条件下可能呈现负相关因为它们是光化学反应的不同产物。做相关性分析的目的有两个一是了解哪些污染物对AQI贡献最大二是判断是否存在多重共线性问题。如果两个特征相关性超过0.9建模时可以考虑只保留其中一个或者用主成分分析降维。我一般会画一个相关性热力图直观地看哪些变量之间关系紧密。但要注意相关性不等于因果性PM2.5和PM10高度相关不代表它们可以互相替代因为它们在AQI计算中的权重不同。4.3 异常值的识别与处理AQI数据中的异常值有两种一种是真实的极端污染事件比如沙尘暴或烟花爆竹集中燃放导致的短时高浓度另一种是数据采集或传输错误导致的虚假异常。区分这两种异常值很重要。真实的极端事件不应该被删除因为它们是模型需要学习的正常模式的一部分。虚假异常则需要修正或删除。判断方法可以结合多个字段一起看如果AQI异常高但六项污染物浓度都正常那很可能是AQI字段本身有问题如果多项污染物同时异常高那大概率是真实事件。我通常用四分位距法来初步标记异常值然后人工检查被标记的记录。对于确认是数据错误的记录用前后时刻的插值替换对于真实极端事件保留不动。5. 模型选型与训练从基线到进阶5.1 基线模型先跑通再优化很多人一上来就想用深度学习结果调了半天参数还不如一个线性回归。我的建议是先建立一个简单的基线模型比如用历史同时刻的AQI均值作为预测值或者用前一天的AQI作为预测值。这个基线看起来简陋但它能给你一个误差的参考下限。然后可以试线性回归和决策树。线性回归的好处是可解释性强你能直接看到每个特征的系数大小和方向。决策树的好处是能自动捕捉非线性关系但单棵树容易过拟合所以通常用随机森林或梯度提升树。我在实际项目中的经验是对于AQI预测梯度提升树类模型比如XGBoost、LightGBM在大多数情况下表现最好训练速度也快调参相对容易。随机森林次之线性回归在特征工程做得好的情况下也能达到可接受的水平。5.2 时间序列交叉验证的正确做法时间序列数据不能用普通的K折交叉验证因为那会导致未来数据泄漏到训练集中。正确的做法是使用时间序列交叉验证也叫滚动窗口验证。具体来说把数据按时间顺序分成若干段每次用前面的数据训练用紧接着的一段验证然后窗口向前滑动。这样能模拟真实预测场景评估结果更可靠。from sklearn.model_selection import TimeSeriesSplit tscv TimeSeriesSplit(n_splits5) for train_idx, val_idx in tscv.split(X): X_train, X_val X.iloc[train_idx], X.iloc[val_idx] y_train, y_val y.iloc[train_idx], y.iloc[val_idx] # 训练和评估模型这个细节看起来小但影响很大。我见过有人用普通交叉验证得到很好的结果上线后效果大打折扣就是因为数据泄漏导致评估过于乐观。5.3 特征重要性分析与模型解释模型训练完之后不要只看误差指标还要看特征重要性。梯度提升树类模型都提供特征重要性输出能告诉你哪些特征对预测贡献最大。从我做过的项目来看滞后特征和滑动窗口统计通常排在重要性前列这符合直觉因为AQI的时间自相关性很强。气象特征中风速和湿度的贡献通常比较大。时间特征中月份和小时的重要性较高星期的重要性相对较低。如果发现某个特征重要性异常高要警惕数据泄漏。比如当前时刻的PM2.5浓度如果被当作特征那它和AQI的关系几乎是确定性的模型会过度依赖这个特征导致在其他场景下失效。提示特征重要性只能反映特征在训练集上的贡献不能直接解释为因果关系。分析时要结合领域知识判断合理性。6. 常见问题与排查技巧实录6.1 模型在测试集上表现差怎么办这是最常见的问题。排查顺序建议如下排查项可能原因解决方法数据泄漏训练时用了未来信息检查所有特征是否只依赖当前及过去数据分布偏移训练集和测试集时间跨度差异大检查两个时间段的数据分布是否一致过拟合模型太复杂或特征太多减少特征、增加正则化、降低模型复杂度欠拟合模型太简单增加特征、换更复杂的模型评估指标指标选择不当确认指标与业务目标一致我遇到最多的情况是数据泄漏和分布偏移。数据泄漏前面说过了分布偏移在AQI预测中也很常见因为不同季节、不同年份的污染模式可能变化很大。如果训练集是夏季数据测试集是冬季数据模型表现差是正常的这时候需要考虑按季节分别建模或者在特征中加入季节标识。6.2 预测值总是偏保守怎么办梯度提升树类模型有个特点预测值倾向于向均值靠拢极端高值和极端低值都预测不准。这在AQI预测中表现为轻度污染时预测偏高重度污染时预测偏低。这个问题的根源是损失函数。默认的均方误差损失对大误差的惩罚是平方级的模型为了降低整体误差会选择“安全”的中间值。解决方法有两个一是改用分位数损失或Huber损失让模型对极端值更敏感二是对训练样本加权给极端值更高的权重。我试过用分位数回归来预测AQI的90分位数效果比直接预测均值好很多特别是在重污染预警场景下更有实用价值。6.3 特征维度太高怎么降特征工程做多了维度很容易上百。维度太高会导致训练慢、过拟合风险增加。降维方法有几种基于特征重要性筛选只保留重要性排名前N的特征基于相关性筛选去掉高度相关的冗余特征主成分分析把原始特征投影到低维空间递归特征消除逐步剔除对模型贡献小的特征我的习惯是先用特征重要性筛一轮再用相关性分析去掉冗余通常能把维度降到原来的三分之一左右模型效果基本不损失训练速度提升明显。6.4 实操避坑清单最后整理一份我在AQI预测项目中踩过的坑和对应的规避方法不要忽略单位统一合并数据前先检查量纲不要用未来数据构造特征所有滞后和滑动统计都要shift不要用普通交叉验证时间序列必须用滚动窗口不要只看整体误差分季节、分污染等级看误差更有意义不要过度追求模型复杂度特征工程到位后简单模型也能有好效果不要忘记保存特征处理管道线上预测时要保证处理逻辑一致不要忽视数据的时间连续性缺失整段时不要硬填这个项目后续还可以往几个方向扩展一是加入更多外部数据比如交通流量、工业排放数据二是尝试深度学习模型比如LSTM或Transformer看能否捕捉更复杂的时间依赖三是做多步预测不只预测下一小时而是预测未来24小时或72小时的AQI变化趋势。每个方向都有不少细节可以深挖等后面有机会再单独展开聊。