ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

机器学习实战:AQI分析与预测的完整流程与避坑指南

机器学习实战:AQI分析与预测的完整流程与避坑指南 简介面向机器学习初学者与环境数据分析人员这份资源以空气质量指数AQI为实战主题数据集涵盖PM2.5、PM10、NO2、SO2等污染物浓度与温度、湿度、风速等气象因素基于Python和pandas等库完成从数据清洗、缺失值与异常值处理、标准化/归一化到探索性分析与回归建模线性回归、随机森林、GBDT等的全流程演示。资源包共33个文件、约4.23MB包含2个Jupyter Notebook代码、1份csv数据集、2个Markdown说明文档、2个HTML可视化页面含地图展示以及24张PNG结果图表可直接对照运行。目前已有197人学习下载。通过这套真实环境数据案例可以掌握PM2.5、PM10等污染物浓度与气象因素对AQI的影响分析理解交叉验证与MSE、RMSE、R²等常用评估指标的含义学会用可视化图表呈现预测效果。项目结构清晰附带说明文档便于自学和在此基础上扩展改进。1. AQI分析与预测为什么这个机器学习项目值得完整做一遍2023年冬天华北某市AQI连续两天爆表环保部门的公众号推送都是「重污染橙色预警」但前一天的气象预报并没有预报出这个级别。手头只有三年的空气质量监测历史数据能不能用机器学习在当天预测第二天的AQI至少给应急响应留出半天时间这个问题就是「机器学习-03-AQI分析与预测」项目解决的核心诉求用一份包含污染物浓度、气象条件、时间信息的表格数据训练一个能预测未来24小时空气质量指数的模型。它不涉及图像、不涉及语音是一个典型的表格型回归任务特别适合机器学习入门阶段练手也适合想转数据挖掘岗的人当作品集。这个项目真正考验人的地方不在模型而在数据。AQI数据的字段多、量纲杂、缺失值集中在重污染时段、时间序列天然有序直接套用随机划分的训练测试集或全局均值填充做出来的模型在验证集上好看一到真实预测就翻车。这篇文章按我自己做这类项目的顺序拆先讲数据怎么清理和构造再讲特征怎么选然后是模型怎么调最后是一份可以直接抄走的滚动验证代码和一份避坑手册。代码基于 Python 的 pandas、scikit-learn、XGBoost数据用公开的监测站历史记录格式来演示你拿自己城市的CSV也能跑通。2. 先把数据搞清楚AQI数据集的字段构成与预处理要点2.1 数据集长什么样字段含义与第一眼质量检查一份完整的AQI历史数据集常见做法是包含两类字段污染物浓度和气象观测。污染物字段一般有 PM2.5μg/m³、PM10μg/m³、SO₂、NO₂、COmg/m³、O₃μg/m³还有一个根据这些浓度折算出来的AQI整数。气象字段常见的是温度℃、相对湿度%、风速m/s、气压hPa。有些公开数据集还会附带站点编号和日期格式上一般是每行一条日记录也有小时级记录需要聚合成日。拿到数据第一件事不是建模是看结构。用 pandas 读进来后先看 info 和缺失情况这一步能发现字段类型错乱、时间索引没解析、缺失占比过高等一堆问题。下面这段是我每次拿到数据都会先跑的检查代码import pandas as pd import numpy as np # 读取数据date 列解析成时间索引 df pd.read_csv(aqi_data.csv, parse_dates[date], index_coldate) df df.sort_index() # 查看字段类型和缺失情况 print(df.info()) print(\n缺失值统计) print(df.isna().sum()[df.isna().sum() 0]) # 看 AQI 与各污染物的大致分布 print(\nAQI 描述统计) print(df[AQI].describe())逻辑说明parse_dates[date]把日期字符串转成时间类型index_coldate把日期设为索引这是后续做滞后特征和滚动预测的前提——时间序列任务必须保证索引有序且是时间类型。isna().sum()统计每列缺失数量只打印有缺失的列避免一堆零输出淹没关键信息。describe()看 AQI 的均值、极值能快速判断数据里有没有异常爆表记录比如 AQI500 说明达到了爆表上限。参数说明如果你的数据里时间列叫别的名字比如time或日期把parse_dates里的字段名换成对应的列名即可。如果原始数据是小时级不要急着聚合先看完整性再决定怎么重采样。sort_index()这一步别省略时间乱序会让后面所有滞后特征全错。2.2 缺失值处理别一上来就 fillna 均值AQI数据的缺失不是随机的重污染当天、传感器故障时段最容易缺失。比如 PM2.5 浓度很高导致仪器量程超限或者冬季低温影响仪器这时那段数据会直接缺失或变成异常值。如果用全局均值填充等于把重污染时段拉平到普通水平模型学到的规律就是「AQI永远不会太高」预测自然偏保守。我处理时间序列缺失的优先级是前向填充优先于插值插值优先于删除删除优先于全局填充。前向填充ffill()的含义是「用上一个有效时刻的值补当前缺口」对短时缺失很合理因为污染物浓度有惯性一个小时前和现在不会突变。若缺失超过两个采样点我会用interpolate(methodlinear)做线性插值或者直接放弃这段视数据量决定# 对污染物列做前向填充 线性插值注意顺序不能反 df[PM2.5] df[PM2.5].ffill().interpolate(methodlinear) df[PM10] df[PM10].ffill().interpolate(methodlinear) # 对缺失超过 3 天的连续缺口直接标记为 NaN 并删除 for col in [PM2.5, PM10, NO2, O3]: df[col] df[col].mask(df[col].isna().groupby(df[col].notna().cumsum()).transform(count) 3) df df.dropna(subset[PM2.5, PM10])逻辑说明ffill()先解决单点缺失interpolate(methodlinear)再对剩余缺口按线性趋势补值。第三段代码用notna().cumsum()给连续缺失区间分组transform(count)统计每个连续缺失段长度长度大于 3 的置回 NaN最后dropna删掉这些不可靠的行。这样做的理由是连续多天的缺失已经没法用插值还原硬补只会给模型输入一段假数据。参数说明这里的「3天」阈值不是固定值。你数据总共一年连续缺 3 天占比不大可以删数据只有三个月删 3 天可能损失重要季节性样本阈值可以放宽到 7 天。判断标准只有一个补出来的数据不能改变原序列的波动形态。2.3 时间对齐与聚合小时数据怎么变成日均值很多公开数据集存的是小时级记录但 AQI 指数本身是 24 小时滑动平均折算出来的预测「明天 AQI」在业务上也是按天粒度来决策所以必须把小时数据聚合成日数据。聚合时要小心三件事时区是否统一、是否存在重复索引、聚合函数选均值还是中位数。# 如果存在同一时刻多条记录先按时间聚合去重 df_hourly df_hourly.groupby(level0).mean() # 按天聚合污染物取日均AQI 取当天最后一个值或日均均可 df_daily df_hourly.resample(D).agg({ PM2.5: mean, PM10: mean, NO2: mean, O3: mean, AQI: mean, # 业务上也可取一天中的最大 AQI按需求调整 temp: mean, humidity: mean, wind_speed: mean }).dropna()逻辑说明groupby(level0).mean()处理的是同一时间戳有多条记录的情况比如两个监测站的数据拼在一起没去重这一步把重复时刻先合并。resample(D)按天重采样agg里指定每列的聚合方式污染物和气象都用均值AQI 用均值还是最大值取决于你的业务目标——预测峰值预警用最大值预测日均暴露水平用均值。参数说明resample要求索引是 DatetimeIndex如果之前parse_dates没设置成功这一步会直接报错报错信息一般是Only valid with DatetimeIndex。遇到这个错回头检查 CSV 里的日期格式常见的是2023/1/1这种格式 pandas 也能解析但如果日期列混了文本就要先pd.to_datetime强制转换。3. 特征工程怎么做滞后项、气象因子与时间窗口的选择3.1 滞后特征让模型看见昨天的污染惯性AQI 最大的预测因子其实就是昨天的 AQI。污染物在大气中有停留时间今天 PM2.5 高明天往往也低不下来这个特性对应到特征上就是滞后特征。滞后 1 天表示「昨天的 AQI 是多少」滞后 2 天表示「前天」滞后 7 天可以捕捉一周前的水平帮助模型学到周期性。构造滞后特征用shift()但有一个经常踩的坑shift()会引入 NaN因为序列开头没有前置值。这些 NaN 行要删掉否则模型会拿着 NaN 训练# 构造 AQI 滞后特征同时保留污染物滞后 for lag in [1, 2, 3, 7]: df[faqi_lag_{lag}] df[AQI].shift(lag) df[fpm25_lag_{lag}] df[PM2.5].shift(lag) # 删除因 shift 产生的缺失行 df df.dropna() # 验证滞后特征是否和 AQI 相关 print(df[[AQI, aqi_lag_1, aqi_lag_2, aqi_lag_7]].corr()[AQI])逻辑说明shift(lag)把整列向下移 lag 行aqi_lag_1的第 t 行就是原始 AQI 的第 t-1 行正好对应昨天的值。最后打印相关矩阵你会看到aqi_lag_1的相关系数通常在 0.7 以上这个数值可以直接说明滞后特征在这个任务里的地位。如果相关系数低于 0.5说明数据质量问题或该地区污染受外来源影响大后续模型要更依赖气象特征。参数说明滞后天数不是越多越好。加 1、2、3、7 天是常见做法但加 30 天、60 天反而会引入噪音因为 30 天前的污染对今天几乎没有物理相关性。如果数据量大、模型是树模型多放几个滞后让它自己选不会有大问题如果是线性回归滞后特征之间高度自相关会导致多重共线性系数解释性变差。3.2 气象与日历特征温度差、湿度、周末标记污染物浓度和气象条件强相关逆温导致污染物积聚、大风扩散、降雨清除。常见的做法是把气象原始值直接放进特征再加一阶差分比如「今天和昨天温度差」能反映是否有冷暖空气过境。日期特征也不能漏AQI 在工作日和周末有明显差异因为机动车排放和工地活动不同。# 气象一阶差分温差、湿度差、风速差 df[temp_diff] df[temp] - df[temp].shift(1) df[humidity_diff] df[humidity] - df[humidity].shift(1) df[wind_diff] df[wind_speed] - df[wind_speed].shift(1) # 日历特征星期几、是否周末、月份 df[weekday] df.index.dayofweek df[is_weekend] (df.index.dayofweek 5).astype(int) df[month] df.index.month # 风向如果有角度字段拆成 sin/cos 两个分量 if wind_direction in df.columns: df[wind_dir_sin] np.sin(np.deg2rad(df[wind_direction])) df[wind_dir_cos] np.cos(np.deg2rad(df[wind_direction])) df df.drop(columns[wind_direction])逻辑说明shift(1)的差值是让模型学到「温度骤降」这类变化信号空气污染和气象变化的关系往往比绝对数值更直接。dayofweek输出 0-6 的整数is_weekend把周六日变成 1这两列对树模型是有效特征。风向是环形变量0° 和 360° 本质相同直接编码是 0 和 360 的差距对模型来说像两个极端数值拆成 sin/cos 后变成两个连续分量模型能理解角度相似性。参数说明月份特征会引入季节性但冬季污染重、夏季轻模型可以从月份学到这一点。要注意的是加入了month后模型对新数据的预测前提是「季节性规律稳定」如果某个冬天出现极端气象模型会低估重污染这不是特征的问题而是数据里没有见过类似组合。3.3 特征选择与泄漏检查哪些特征留、哪些必须删特征不是越多越好有两个特征必须排查。第一个是目标变量的「未来值」比如AQI当天已经折算到数据里了如果你不小心把 O₃ 的小时最大值当作日特征而 AQI 也依赖 O₃ 计算这不算泄漏真正的泄漏是你在预测当天时用到了当天才产生的数据比如当天的风速日均值。做预测时用「前一天 20 点之前能拿到的数据」构建特征是最稳妥的边界。第二个要排查的是强相关冗余特征。PM2.5 和 AQI 的相关系数往往超过 0.9如果目标是预测 AQIPM2.5 作为特征可以保留因为 AQI 不是全部由 PM2.5 决定但如果你发现 AQI 和某个特征完全线性相关比如从同一个公式推导的中间量就该删。# 检查候选特征之间的相关性超过 0.95 的标记出来 feature_cols [c for c in df.columns if c ! AQI] corr_matrix df[feature_cols].corr().abs() upper corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k1).astype(bool)) high_corr [(col, row) for col in upper.columns for row in upper.index if upper.loc[row, col] 0.95] print(高相关特征对, high_corr)逻辑说明np.triu(k1)取出相关矩阵的上三角部分避免把每个特征自己和自己的相关性必然为 1算进去也避免重复输出对称位置的相同特征对。筛选阈值 0.95 表示这两个特征携带的信息几乎一样建议删掉其中一个保留物理含义更直接的那个。参数说明0.95 是一个偏保守的阈值。树模型对高相关特征不敏感删不删结果差异不大线性回归模型则必须处理否则系数方差膨胀预测不稳定。如果你后续用 Lasso 或岭回归高相关特征可以保留正则化会自动压低冗余特征的权重。4. 模型选型与调参从线性回归到 XGBoost 的完整对比4.1 基线模型线性回归的价值与局限第一个模型一定用线性回归它不是为了拿最佳效果而是为了建立一条底线、验证特征是否有效。线性回归假设目标与特征呈线性关系AQI 与污染物浓度大体上是线性换算但与气象条件的关系存在非线性所以线性回归通常能给出一个「还可以但不精准」的结果。用它跑一遍能得到两个信息特征整体有没有预测力残差里是否存在明显模式。from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_absolute_error, mean_squared_error # 按时间顺序切分前 80% 训练后 20% 测试 train_size int(len(df_clean) * 0.8) train_df df_clean.iloc[:train_size] test_df df_clean.iloc[train_size:] features [c for c in df_clean.columns if c ! AQI] lr LinearRegression() lr.fit(train_df[features], train_df[AQI]) pred_lr lr.predict(test_df[features]) mae_lr mean_absolute_error(test_df[AQI], pred_lr) rmse_lr np.sqrt(mean_squared_error(test_df[AQI], pred_lr)) print(fLinear Regression — MAE: {mae_lr:.2f}, RMSE: {rmse_lr:.2f})逻辑说明必须按时间顺序切分而不是train_test_split(random_state42)随机切。随机切会让模型在训练时见过测试时段附近的样本等于偷看了答案测出来的误差虚低。iloc[:train_size]按行序号切因为数据已经按时间排序前 80% 是历史后 20% 是未来。参数说明MAE和RMSE使用 sklearn 的默认实现均以 AQI 单位输出。AQI 通常在 20-300 之间波动如果 MAE 在 20 左右说明预测平均偏移 20 个指数点这个精度对日常预报够用但对重污染预警不够。注意观察 RMSE 与 MAE 的差距如果 RMSE 明显大于 MAE说明存在少数预测误差特别大的样本通常是重污染日被低估。4.2 树模型调参XGBoost 的四个关键参数线性回归之后换成 XGBoost原因是它能学习特征之间的交互和非线性关系。比如「低温 高湿 低风速」三个条件叠加才导致重污染线性模型很难自己组合出这个交互项树模型天然做得到。XGBoost 的默认参数就能赢过线性回归不少但要让它在验证集上稳定四个参数必须调。import xgboost as xgb # 第一次用一组保守参数跑通流程 model_xgb xgb.XGBRegressor( n_estimators300, max_depth5, learning_rate0.05, subsample0.8, colsample_bytree0.8, random_state42 ) model_xgb.fit(train_df[features], train_df[AQI]) pred_xgb model_xgb.predict(test_df[features]) mae_xgb mean_absolute_error(test_df[AQI], pred_xgb) rmse_xgb np.sqrt(mean_squared_error(test_df[AQI], pred_xgb)) print(fXGBoost — MAE: {mae_xgb:.2f}, RMSE: {rmse_xgb:.2f})逻辑说明fit时传入训练集的特征和目标树模型逐步分裂每棵树拟合前一棵的残差learning_rate控制每棵树贡献的权重学习率小意味着每棵树的步子小、需要更多树。random_state42固定随机种子保证实验可复现换不同的项目数字无所谓但固定了就不能改。参数说明四个关键参数的作用分别是——max_depth5限制每棵树最多分裂 5 层太深会过拟合训练集AQI 数据量通常在几百到几千行深度 3-6 是合理区间learning_rate0.05是步长常用范围 0.01-0.1越小精度越高但树要越多、训练越慢subsample0.8表示每棵树随机用 80% 的样本训练防止过拟合colsample_bytree0.8表示每棵树随机选 80% 的特征增加树之间的多样性。如果你的数据很小少于一千行subsample可以调到 0.9避免样本太少导致每棵树学到的分布偏差过大。4.3 评估指标的取舍MAE、RMSE 与峰值预测能力很多人只看 MAE 或 R²对 AQI 预测来说这不够。AQI 分布的尾部是重污染日这些样本数量少但业务价值巨大。一个模型的 MAE 为 15如果这个误差全来自普通天气日重污染日全部低估那它毫无预警价值。所以我一般同时看三个数MAE、RMSE、重污染区间AQI 150的单独 MAE。# 计算全部样本与重污染样本的指标对比 for name, y_true, y_pred in [(LR, test_df[AQI], pred_lr), (XGB, test_df[AQI], pred_xgb)]: mae_all mean_absolute_error(y_true, y_pred) # 重污染样本真实 AQI 大于 150 mask_heavy y_true 150 if mask_heavy.sum() 0: mae_heavy mean_absolute_error(y_true[mask_heavy], y_pred[mask_heavy]) else: mae_heavy float(nan) print(f{name}: MAE{mae_all:.2f}, 重污染MAE{mae_heavy:.2f})逻辑说明mask_heavy y_true 150从测试集里过滤出真实 AQI 大于 150 的行对这些行单独计算 MAE。AQI 等级划分里 150 是轻度污染的边界重污染以上样本在一年数据里可能只有几十条如果这些条目的 MAE 比整体 MAE 大一倍以上说明模型对极端情况不敏感调参方向应该更关注特征而不是模型结构。参数说明阈值 150 按中国 AQI 等级标准取的如果你的业务更关注「中度污染」就取 100。这个指标不用严格对比模型之间谁更低重点看同一个模型在普通日和重污染日的误差差距差距大说明特征里缺少诱发重污染的物理信号比如缺少边界层高度、逆温强度这类气象专业变量。5. 避坑手册AQI 预测最常见的 5 个翻车现场5.1 随机切分数据集模型在测试集上虚高现象用train_test_split不设shuffleFalse或者设了random_state但没按时间切训练出一套 MAE 只有 8 的模型放到真实环境却差到不可用。原因AQI 序列前后日高度自相关随机切分会把某一天的数据一部分放进训练集、一部分放进测试集模型实际上在预测「已经见过的日子」这就是时间序列里的数据泄漏。解决一律用train_df df.iloc[:int(len(df)*0.8)]按位置切或使用TimeSeriesSplit做交叉验证。判断自己有没有切对的办法是检查训练集和测试集的时间范围有没有重叠打印两段的min(index)和max(index)即可。5.2 用当天的气象日均值预测当天 AQI现象特征里包含temp、wind_speed当天的日均值模型效果惊人MAE 压到 10 以内上线后发现根本没法用——因为预报未来的时刻当天的气象观测数据还没产生。原因这是典型的特征泄漏。AQI 和当天气象是同时段观测的预测「明天的 AQI」时你能拿到的只有明天的气象预报值而不是明天的实测值。用实测值训练等于把未来信息泄露给了模型。解决严格按时间对齐。预测第 t 天的 AQI特征只允许包含截止第 t-1 天 24 点之前能拿到的数据。气象特征如果用的是预报值训练时也要用「前一天的实况值 预报误差模拟」去拟合或者干脆只用滞后气象特征。检验方法把你认为的「预测时刻」和「特征产生时刻」列出来特征产生时间早于预测时刻才算合格。5.3 缺失值集中在重污染日fillna 均值把峰值抹平现象PM2.5 列在冬季缺失率特别高用df.fillna(df.mean())补齐后训练模型对所有重污染日都预测成普通水平重污染 MAE 突破 80。原因传感器在浓度过高时可能失效或数据传输中断导致缺失和重污染强相关。全局均值是普通水平填充后重污染样本被系统性篡改模型学不到「什么条件下 AQI 会飙升」。解决先看缺失的时间分布用df[PM2.5].isna().resample(M).sum()按月统计缺失量。如果缺失集中在冬季处理策略应该是单点缺失用ffill()补连续缺失超过阈值就删除该时段最后再看一眼填充后的序列在重污染日是否还有峰值。还有一个保险做法把「是否缺失」本身做成一个特征模型可以学到缺失发生时段往往伴随异常污染。5.4 滞后特征把不可获得的未来信息带进预测现象构造aqi_lag_1后模型效果好但在滚动预测时发现 lag 特征取的是预测日当天的值实现逻辑和训练逻辑对不上线上效果断崖下跌。原因训练时 DataFrame 里aqi_lag_1恰好是「上一行」的 AQI这个上一行在训练集里是真实的。但如果你的预测目标是「未来第 3 天」第 t3 天的aqi_lag_1应该是第 t2 天的 AQI而第 t2 天还没发生此时你可能错误地用第 t 天的 AQI 去填了。滞后步长和预测步长不匹配。解决记住一个规则预测目标h天后可用的滞后特征最大滞后h-max不能小于预测步长。预测明天h1lag_1可用预测后天h2lag_1的取值来自明天而明天尚未发生所以不能用只能从lag_2开始。实现时把预测目标从「当天 AQI」改成「h 天后的 AQI」比如df[target] df[AQI].shift(-h)然后用匹配的滞后特征。5.5 只看整体 MAE忽略重污染日全部漏报现象模型整体 MAE 15看着不错但画预测图和真实值对比发现 AQI 超过 200 的日子模型预测值都在 120 左右一次重污染都没抓住。原因整体 MAE 被占多数的好天气样本拉低重污染样本占比不到 5%它们贡献的误差在平均值里微不足道。业务上重污染漏报的代价远高于普通日误差 20 点。解决在评估阶段把样本按 AQI 等级分组分别算 MAE 和命中率。定义「重污染预警命中」为真实 AQI 150 且预测值 150允许一定缓冲比如预测 130 也算命中统计命中率。如果命中率低于 60%说明模型没有学到重污染的触发条件需要补气象特征或换模型而不是继续调max_depth。6. 让预测真正可用滚动验证与误差复盘实验室里的「一次性切分」评估和真实部署有一个关键差异真实系统每天要预测新的一天每过一天那天的真实 AQI 会出炉并成为新样本。滚动验证walk-forward validation模拟的就是这个过程——每预测完一天把它并进训练集再预测下一天。这比一次性切分更贴近生产也更严格。# 滚动验证逐步预测测试集后 30 天 n_test 30 preds_rw, actuals_rw [], [] model_rw xgb.XGBRegressor( n_estimators100, max_depth4, learning_rate0.05, subsample0.8 ) for i in range(n_test): # 每次用截至预测日前一天的数据训练 train_end len(df_clean) - n_test i train_part df_clean.iloc[:train_end] test_row df_clean.iloc[train_end:train_end 1] model_rw.fit(train_part[features], train_part[AQI]) pred model_rw.predict(test_row[features])[0] preds_rw.append(pred) actuals_rw.append(test_row[AQI].values[0]) # 滚动验证的整体误差 resid_rw np.array(actuals_rw) - np.array(preds_rw) print(f滚动验证 MAE: {np.mean(np.abs(resid_rw)):.2f}, RMSE: {np.sqrt(np.mean(resid_rw**2)):.2f})逻辑说明train_end从len(df_clean) - n_test开始逐步加 1保证第 i 次迭代时训练集恰好包含截至预测日前一天的所有数据。test_row是当前要预测的那一天。每次重新fit一个模型模拟「每天早上用全部可得历史数据训练一次」的生产节奏。n_estimators100是为了演示速度正式场景可以提高到 300 并配合早停但滚动验证每步重训练树太多会很慢可以在验证阶段先用小规模参数确认流程没问题再放大。误差复盘这一步很多人跳过但它才是决定模型能不能投入使用的关键。把滚动预测的残差按月份和 AQI 等级画出来你会直观看到模型在哪类日子最容易犯大错。我一般用一段简短的代码做分组统计# 按 AQI 等级统计滚动预测误差 df_result pd.DataFrame({actual: actuals_rw, pred: preds_rw}) df_result[level] pd.cut( df_result[actual], bins[0, 50, 100, 150, 500], labels[优, 良, 轻度, 中度以上] ) print(df_result.groupby(level, observedTrue).apply( lambda g: pd.Series({ 样本数: len(g), MAE: np.mean(np.abs(g[actual] - g[pred])) }) ))逻辑说明pd.cut按 AQI 国家标准把真实值分成四档groupby(level).apply对每个等级分别计算样本数和 MAE。通常你会看到「优」和「良」的 MAE 在 10-20而「中度以上」的 MAE 翻倍。这个结果直接告诉你两件事模型对日常污染把握尚可但重污染触发机制没学透下一步该投入的方向是补充气象垂直数据如边界层高度、逆温层强度而不是继续调参。我的习惯是每次做完滚动验证把残差最大的 5 天打印出来看一下那几天发生了什么——用记忆搜索当时的天气事件或污染源信息。十次里有八次会发现大误差的日子不是普通气象条件而是突发沙尘或区域传输这类事件在纯粹的历史表格里几乎没有预兆。想落到实处就要在特征层面加入上游城市的污染数据或者引入气象预报的边界层变量。这些都属于同一个方向的延伸做好滚动验证你才知道下一步该往哪走。对于刚接触这个项目的人来说先把滚动验证跑通、把滞后特征的时间逻辑理顺AQI 预测的骨架就算立住了剩下的是锦上添花。希望帮到你。本文还有配套的精品资源点击获取
返回列表