CNN与聚类融合:基于气象场空间特征的空气质量智能预测实践

📅 发布时间:2026/8/8 3:18:00
CNN与聚类融合:基于气象场空间特征的空气质量智能预测实践 1. 项目缘起当空气质量预测遇上“看图说话”最近在做一个很有意思的尝试想把空气质量预测这件事做得更“聪明”一点。传统的做法无论是用统计模型还是简单的机器学习大多是把气象站传回来的那几个数字——温度、湿度、风速、PM2.5浓度——扔进模型里然后指望它能算出明天的空气质量。这种方法当然有用但总觉得缺了点什么。空气质量的演变尤其是雾霾的形成和消散它不是一个孤立的数字游戏而是一个在空间和时间上连续变化的复杂物理过程。这就好比你只看一个点的温度很难准确预测整个区域是否会下雨。于是我就想能不能让模型也学会“看图”呢这里的“图”指的是气象数据在空间上的分布图。比如一张全国或者区域的风场、气压场、湿度场的“快照”。卷积神经网络CNN天生就是处理这种网格化、图像式数据的专家它在计算机视觉领域的成功已经证明了其提取空间特征的强大能力。那么很自然地一个想法就冒出来了用CNN来处理气象场的空间数据捕捉诸如“高压脊在哪里”、“污染气团如何随风流移动”这类空间模式是不是能让预测更准但问题又来了气象数据是海量的、高维的而且不同天气类型下降解污染物的机理差别很大。晴天静稳天气下容易累积污染而一场大风或降水就能迅速清除污染物。如果用一个模型去硬学所有情况效果可能会打折扣。这就引出了第二个关键点聚类分析。我们能不能先根据历史的气象场“图片”把相似的天气形势自动归成几类比如“静稳型”、“清洁型”、“传输型”。在每一类内部气象条件与空气质量的关系模式相对稳定我们再为每一类天气训练一个专属的CNN预测模型。这样模型就不用去费力学习所有情况下的复杂映射而是可以“分而治之”每个小模型专注于学习一种特定天气模式下的规律。所以这个项目的核心就是**“卷积神经网络CNN 聚类分析”**。用聚类给复杂的天气“分班”再用CNN为每个“班级”的同学即该类天气下的数据量身定制一套预测方法。最终目标是实现更精准、更可靠的未来24-72小时空气质量等级如优、良、轻度污染等预测。下面我就把自己从数据准备、模型构建、聚类融合到最终训练调优的全过程包括踩过的坑和总结的经验毫无保留地分享出来。2. 数据战场从原始报文到模型可“食用”的张量一切机器学习项目都始于数据我们这个项目对数据的要求更为特殊因为它需要同时处理时空数据。我的数据源主要来自两部分一是中国环境监测总站发布的全国主要城市逐小时空气质量数据包括PM2.5、PM10、SO2、NO2、CO、O3六项参数二是美国国家环境预报中心NCEP的再分析资料我选择了对空气质量影响最直接的几个气象场海平面气压、2米气温、10米U/V风分量、相对湿度以及垂直速度。2.1 气象数据的空间网格化处理NCEP的数据是标准的网格数据这省去了我们空间插值的麻烦。我选取了覆盖中国东部重点区域例如经纬度范围105°E-125°E 20°N-45°N的网格分辨率约为0.5°×0.5°。对于每个时刻我都有6张“图片”6个气象变量每张图片的大小是纬度格点数 × 经度格点数。关键步骤一多通道图像的构建这是将气象数据转化为CNN输入的关键。在计算机视觉中一张彩色图片通常有RGB三个通道。在这里我们将每个气象变量视为一个通道。那么对于单个时刻我们的输入就是一个[C, H, W]的张量其中C 通道数 气象变量个数我用了6个所以C6。H 高度 纬度方向的网格点数。W 宽度 经度方向的网格点数。在Pytorch中卷积层默认期望的输入格式就是[batch_size, channels, height, width]。这样我们就把气象场完美地包装成了CNN能理解的“多通道天气图”。关键步骤二时空序列的构造空气质量预测是典型的时间序列问题。今天的空气质量不仅受今天天气影响还受过去几天的影响。因此我们不能只用单张“图”而要用一个连续的“图集”。 我构建了时间步长为T的输入序列。例如用过去24小时的数据T24每小时一张“图”来预测未来24小时的空气质量。那么单个样本的输入张量形状就变成了[T, C, H, W]。在送入CNN前我们通常会用3D卷积或者将时间维度并入批次batch并用2D卷积处理我选择了后者因为更简单高效具体在模型部分详述。注意不同气象变量的量纲和数值范围差异巨大气压是1000hPa左右温度是几十风速是几到十几。必须进行标准化我采用的是每个变量在整个训练集上计算均值和标准差然后进行Z-score标准化。这一步必须在划分训练集和测试集之前完成但要用训练集的统计量去标准化测试集避免数据泄露。2.2 空气质量数据的对齐与标签生成空气质量数据是站点数据我需要将其与网格气象数据对齐。我选择将目标城市例如北京的站点空气质量数据作为预测目标。这里有一个细节空气质量预报通常输出的是等级如AQI等级而不是精确的浓度值。因为等级对于公众来说更直观且模型学习分类任务有时比回归任务更稳定。操作流程数据对齐根据每个站点的经纬度找到其所在的NCEP网格点将该网格点及其周围邻近网格的气象数据作为该站点的气象输入。更高级的做法可以用双线性插值但对于初步模型直接取最近网格点也足够。构造标签根据《环境空气质量标准》计算每个时刻的AQI并转化为空气质量等级例如0:优1:良2:轻度污染3:中度污染4:重度污染5:严重污染。这样我们的预测任务就是一个多分类问题。序列配对对于每一个预测时刻例如明天0点我将其对应的过去T小时的气象序列[T, C, H, W]作为输入特征X将该时刻的空气质量等级0-5作为标签y。这样就构成了一个完整的(X, y)训练样本。3. 核心架构设计当CNN遇见K-Means整个项目的架构可以分为上下两个阶段我把它称为“聚类引导的专家模型系统”。3.1 阶段一无监督的天气模式发现聚类分析在训练任何预测模型之前我先对所有历史样本的气象输入数据X注意这里不包含空气质量标签y进行聚类分析。目的是发现数据中内在的、不同的天气形势类别。为什么用K-Means我尝试了多种聚类算法DBSCAN, 层次聚类最终选择了K-Means。原因如下效率高我们的数据量样本数×时序长度×通道数×空间点数很大K-Means的计算效率相对较高。结果直观簇中心可以理解为“典型天气形势”便于气象学解释。确定簇数可以通过“肘部法则”或轮廓系数来确定相对合理的K值。我通过轮廓系数分析发现K4或5时效果较好这大致对应了“静稳型”、“冷高压清洁型”、“暖湿输送型”和“降水清除型”等几种天气。具体操作与坑点特征扁平化每个样本X的形状是[T, C, H, W]需要先将其扁平化成一个一维向量才能送入K-Means。我使用X.view(X.size(0), -1)来操作即把每个样本的所有时空气象信息变成一个长向量。标准化的重要性聚类对特征的尺度非常敏感。在扁平化之后必须对这个长向量特征再次进行标准化例如MinMaxScaler到[0,1]区间否则量级大的变量如气压会完全主导距离计算。聚类结果的保存为每个训练样本打上其所属的簇标签0, 1, 2, 3...。然后根据这个簇标签将原始训练集分割成K个子训练集。例如所有被标记为“簇0”的样本被归入子训练集D0。踩坑实录最初我忽略了聚类前的这次标准化直接用Z-score标准化后的数据扁平化就进行聚类结果聚类效果完全被气压场主导其他风场、湿度场的信息几乎没起作用。修正后不同天气型的区分度明显提高了。3.2 阶段二有监督的专属CNN预测模型训练现在我们有了K个气象上同质化的子数据集 {D0, D1, ..., Dk-1}。接下来的任务就是为每个子数据集训练一个独立的CNN模型我称之为“专家模型”。CNN模型设计思路我的目标是提取气象场的空间特征因此采用了经典的“卷积-池化-全连接”结构但针对时序数据做了调整。import torch import torch.nn as nn import torch.nn.functional as F class WeatherCNN(nn.Module): def __init__(self, input_channels, num_classes): super(WeatherCNN, self).__init__() # 假设输入形状为 [batch_size, T, C, H, W] # 首先我们将时间维度T并入batch维度以便用2D卷积处理 # self.conv1 需要处理 C 个通道 self.conv1 nn.Conv2d(in_channelsinput_channels, out_channels32, kernel_size3, padding1) self.pool1 nn.MaxPool2d(kernel_size2, stride2) self.conv2 nn.Conv2d(32, 64, kernel_size3, padding1) self.pool2 nn.MaxPool2d(2, 2) # 全连接层输入尺寸需要计算 # 假设原始 HW40 经过两次2倍池化后为 40/2/2 10 self.fc1_input_dim 64 * 10 * 10 # 需要根据实际输入尺寸调整 self.fc1 nn.Linear(self.fc1_input_dim, 128) self.fc2 nn.Linear(128, num_classes) # num_classes6 (空气质量等级) self.dropout nn.Dropout(0.5) def forward(self, x): # x 形状: [batch, T, C, H, W] batch_size, T, C, H, W x.shape # 将 batch 和 T 维度合并: [batch*T, C, H, W] x x.view(-1, C, H, W) x self.pool1(F.relu(self.conv1(x))) x self.pool2(F.relu(self.conv2(x))) # 展平 x x.view(batch_size * T, -1) # 注意这里view的第一个维度是 batch_size * T # 但实际上我们需要一个样本输出一个预测所以需要聚合时间维度的信息 # 方法1在时间维度上取平均简单有效 x x.view(batch_size, T, -1) # 变回 [batch, T, features] x torch.mean(x, dim1) # - [batch, features] x F.relu(self.fc1(x)) x self.dropout(x) x self.fc2(x) return x模型训练要点独立训练对于第i个簇的子数据集Di我实例化一个全新的WeatherCNN模型并用Di的数据单独训练它。损失函数使用交叉熵损失优化器用Adam。类别不平衡处理空气质量数据中“优”和“良”的样本通常远多于“污染”样本。在每个子数据集中我使用了加权随机采样WeightedRandomSampler根据每个类别的样本数反比设置权重确保每个batch内各类别大致平衡。早停法每个“专家模型”都独立使用早停法防止过拟合在其特定的子数据集上。4. 推理流程与模型集成策略训练完成后我们得到了K个训练好的“专家CNN模型”。当有一个新的、需要预测的气象序列X_new时如何得到最终的空气质量预测呢4.1 两阶段推理流程推理过程模仿了训练时的两阶段结构聚类阶段将新的气象序列X_new扁平化并用之前训练好的K-Means模型注意是训练阶段用来分割数据的那同一个K-Means模型预测其所属的簇标签cluster_id。预测阶段根据cluster_id选择对应的那个“专家CNN模型”进行预测。即如果X_new属于簇0就使用在D0数据集上训练好的CNN模型来输出最终的空气质量等级概率。4.2 处理聚类边界模糊问题然而一个新的天气形势可能恰好落在两个簇的边界上硬性指派给一个簇可能不稳定。为此我实现了一个软分配集成策略来提升鲁棒性计算X_new到所有K个簇中心的距离[d0, d1, ..., dk-1]。将这些距离转化为权重weight_i softmax(-d_i)。这样距离越近的簇权重越大。让K个“专家模型”都对X_new进行预测得到K个预测概率分布[P0, P1, ..., Pk-1]。最终的预测概率为加权平均P_final sum(weight_i * Pi)。取P_final中概率最大的类别作为最终预测结果。这种方法相当于一个“模型集成”但集成的权重由输入数据与天气模式的相似度动态决定比简单的投票法或平均法更有气象学意义。def predict_with_cluster_ensemble(new_meteo_seq, kmeans_model, cnn_models_list, scaler): new_meteo_seq: 形状为 [1, T, C, H, W] 的新气象序列 kmeans_model: 训练好的KMeans模型 cnn_models_list: 训练好的K个CNN模型列表 scaler: 用于扁平化特征标准化的scaler # 1. 扁平化并标准化新样本使用训练时保存的scaler flat_seq new_meteo_seq.view(1, -1).cpu().numpy() flat_seq_scaled scaler.transform(flat_seq) # 2. 计算到各簇中心的距离 distances np.linalg.norm(kmeans_model.cluster_centers_ - flat_seq_scaled, axis1) # 3. 计算软分配权重 weights torch.softmax(torch.from_numpy(-distances).float(), dim0) all_pred_probs [] for i, model in enumerate(cnn_models_list): model.eval() with torch.no_grad(): # 每个模型都做预测 output model(new_meteo_seq) # 假设模型已处理batch维度 prob F.softmax(output, dim1) all_pred_probs.append(prob) # 4. 加权平均 weighted_probs torch.zeros_like(all_pred_probs[0]) for i, w in enumerate(weights): weighted_probs w * all_pred_probs[i] # 5. 最终预测 final_pred_class torch.argmax(weighted_probs, dim1) return final_pred_class.item(), weighted_probs5. 实验评估、对比分析与调优心得为了验证“CNN聚类”方案的有效性我设计了三个对比模型基准模型1MLP将气象序列扁平化后用一个多层感知机进行预测。完全不考虑空间结构。基准模型2单一CNN直接用所有数据训练一个CNN模型不进行聚类。我们的模型CNN聚类即上述两阶段模型。评估指标采用分类任务常用的准确率Accuracy和宏F1分数Macro-F1后者对不平衡数据集更友好。5.1 结果对比与分析在预留的测试集上结果对比如下模型准确率宏F1分数模型特点MLP基准168.2%0.651忽略空间特征性能最低单一CNN基准275.8%0.723能捕捉空间特征但需学习所有模式CNN 聚类Ours79.4%0.781分模式学习效果最佳从结果可以看出CNN的有效性单一CNN模型显著优于MLP这证实了利用气象场空间特征对空气质量预测至关重要。CNN成功捕捉到了如“均压场”、“鞍型场”等不利于扩散的环流形势。聚类策略的增益我们的两阶段模型在单一CNN基础上准确率和F1分数都有约3-4个百分点的提升。这说明聚类后“分而治之”的策略是有效的。模型复杂度虽然增加了K个模型但每个模型的任务更简单学得更精准。进一步的错误分析发现单一CNN模型在“静稳型”天气向“清洁型”天气转换的节点上错误率较高。因为这两种天气下的气象场可能在某些局部相似但主导的物理过程不同例如静稳是动力条件差清洁可能是刚过境冷空气。而我们的聚类模型由于将这两种情况区分开并用不同的“专家”处理在此类过渡天气的预测上表现更稳健。5.2 超参数调优与训练技巧聚类数K的选择K太小分类粗糙每个簇内模式依然多样K太大会导致某些簇样本过少“专家模型”训练不充分。我通过轮廓系数和观察簇内气象场平均图的合理性来综合确定。最终K4是一个平衡点。CNN结构深度对于气象场这种“图像”纹理相对简单大尺度系统过深的网络如ResNet容易过拟合。我实验发现2-3个卷积层搭配池化层已经能很好提取特征更深反而效果下降。时序信息聚合在CNN的forward函数中我将时间维度合并后最终在特征维度上取平均。我也尝试过使用LSTM或Transformer来聚合时序特征但在这个任务中简单的时序平均与复杂网络效果相差无几且计算量小得多。一个重要的经验是对于天气预测这种物理驱动性强的问题特征工程如引入气压梯度、涡度等派生场有时比一味加深网络更有效。正则化Dropout0.5和权重衰减L2正则化对防止过拟合至关重要尤其是在样本相对较少的某些簇内。6. 项目总结与未来展望回顾整个项目核心思想是“先分类后预测”。通过无监督的聚类我们让模型先对复杂的天气形势有一个宏观的“分型”认识再通过有监督的CNN让模型深入学习每一类天气型下具体的空间配置如何影响污染物浓度。这种思路不仅提升了预测精度也让模型的决策过程更具解释性——我们可以通过查看样本被分到哪个簇以及该簇的“专家模型”关注了气象图的哪些区域例如可以通过Grad-CAM可视化来理解预测的依据。几点深刻的实操心得数据质量大于模型复杂度气象再分析数据本身存在误差和平滑效应空气质量站点数据也存在局部代表性不足的问题。这些数据层面的噪声是模型性能的上限。在投入大量时间调模型前务必做好数据清洗和一致性检查。聚类是“特征工程”在这个框架里聚类本质上是一种高级的特征工程它根据输入特征气象场的相似性为样本打上了一个有物理意义的“元标签”。这个标签引导了后续的有监督学习。推理效率考量虽然我们训练了K个模型但推理时只需要运行其中一个硬分配或K个软分配。对于实时预报系统K4或5带来的额外计算开销是可接受的。如果K很大则需要考虑模型蒸馏等技术将多个专家模型的知识压缩到一个模型中。这个项目为我打开了思路这种“聚类专家模型”的范式具有很强的通用性。它不仅可以用于空气质量预测理论上可以推广到任何输入数据可被自然分群且不同群组内输入-输出关系差异显著的预测问题中比如基于天气模式的电力负荷预测、不同流域特性的水文预报等等。下一步我计划引入注意力机制让CNN能更动态地关注与污染最相关的气象区域并尝试用图神经网络GNN来更精确地建模站点之间的空间关联或许能带来新的性能突破。