前阵子跑一个跨十年的空气质量分析项目,在整理数据源时发现一个很尴尬的现状:SO2虽然是大气污染的“老牌”污染物,做酸沉降、燃煤治理、健康暴露评估都绕不开它,可高质量的空间数据反而比PM2.5少一截。PM2.5有各种卫星反演、再分析、网格化产品,SO2却常常只能靠零星站点插值,或者用分辨率很粗的全球模式输出,放到城市尺度根本没法看。后来换到这套中国高分辨率月/日度SO2数据集(2013-2023),很多卡壳的地方一下就顺了。它覆盖2013到2023年整整十年,空间上做到高分辨率网格,时间上同时给出月度和日度两套产品,恰好把“宏观趋势看得清”和“微观过程抓得住”两件事一起解决。
需要这份数据的人,基本跑不出这几类:写大气环境方向论文的研究生和科研人员,做空气质量改善效果评估的环保工作者,算健康暴露风险的环境流行病学研究者,以及想给自己的分析模型加一个高质量环境变量的数据从业者。这篇就把我怎么理解这套数据的结构、平时拿它做哪些分析、实测踩过的坑一次说完。
1. 为什么这套数据集值得关注
1.1 2013年这个起点,选得比想象中讲究
很多做环境数据的人看到2013年这个起点,第一反应是“为什么不是更早”。我最初也这么想,后来把政策节点、监测网络、卫星载荷三条线放在一起看,才发现这个年份确实是国内空气质量数据质量的分水岭。
先说政策面,2013年是“大气十条”落地之年,从那以后空气质量治理从“点状治理”转向“系统治理”,SO2作为燃煤型污染的典型指标,被纳入重点考核。更关键的是监测网的变化,2013年前后国家环境空气质量监测网大规模扩展,国控站点数量从几百个快速增加到上千个,而且2013年开始执行新环境空气质量标准,SO2小时均值、日均值、年均值都有了一套完整可比的口径。
站点数据对卫星反演产品的重要性,业内人都懂——没有地面监测标签,机器学习降尺度模型根本训练不出来。2013年之前,全国SO2有效站点稀疏,很多区域只有一两个城市有监测,这样的标签密度做出来的高分辨率产品,精度没有任何保障。所以无论从治理周期还是从数据质量角度,2013年都是一个非常合理的起点。截至2023年,恰好覆盖了“治理前状态—快速改善—平台期”的完整周期,做政策评估的样本量和时间跨度都够了。
1.2 月度数据和日度数据,根本不是同一件事
这套数据集最吸引我的一点,是同时提供月度和日度两套产品。很多人觉得日度信息量大,月度只是日度的平均,非要用就用日度,实则不然。
日度数据可以捕捉单日强排放事件、重污染过程,也能跟气象数据做事件归因。比如冬季一次典型静稳天气过程,SO2浓度在48小时内从低位爬升到高值,这种细节只有日度产品能给。但日度数据也有明显短板——卫星反演受云遮挡影响很大,单日空间覆盖经常是残缺的,而且单日反演的随机噪声比较大,孤立看某一天的数据,数值稳定性并不好。
月度产品则是把一个月内的有效日值聚合到一起,随机噪声互相抵消,空间覆盖显著改善,数值也更稳健。做季节特征、年际趋势、政策前后对比,月度数据远比日度数据省心。我的习惯是:做趋势和政策评估优先用月度数据,做高污染事件过程和健康短期暴露研究再切到日度数据。两套产品配合使用,比只盯着其中一个要顺手得多。
1.3 高分辨率带来的不只是“好看”
分辨率这个指标,外行看热闹,内行看门道。低分辨率产品不是不能用,是很多研究问题根本支撑不起来。
假设拿1°×1°的全球产品做健康暴露评估,一格大约是100公里见方,一个格子里同时包含了城市核心区、郊区、农田、工业园,浓度被严重平滑。人口最密集的城区和周边农村被平均成同一个数值,估算出来的人口加权暴露必然偏低。换成高分辨率网格后,城市核心区和周边区域能拉开梯度,叠加人口网格时,暴露评估的准确度会有本质提升。
在局地尺度分析里,高分辨率同样重要。比如识别一个工业园对下风向区域的SO2贡献,粗网格根本找不到那个污染源的位置。虽然高分辨率产品的不确定性也会随尺度细化而上升,但信息量和空间区分度带来的收益,明显大于噪声带来的损失。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 从卫星轨道到网格浓度:数据是怎么生成的
2.1 紫外波段的看家本领:卫星怎么“看见”SO2
很多人好奇,SO2在大气里浓度低、分布散,卫星隔着几百公里怎么把它揪出来。这就要说到紫外波段的差分吸收光谱技术。
SO2分子在紫外波段有一套特征吸收结构,和臭氧、二氧化氮这些气体的吸收光谱有明显差异。卫星传感器拿到太阳散射光的光谱后,用差分吸收方法把SO2的微弱吸收信号从混叠的背景里分离出来,就能算出整层大气里的SO2柱总量,单位通常用DU。OMI、OMPS、TROPOMI这些紫外传感器,都是这个路子。
但这里有个关键概念要拎清楚:卫星反演出来的是“对流层SO2柱浓度”,代表从地面到对流层顶一整根气柱里SO2的总量,它不直接等于地面呼吸层的浓度。柱浓度和近地面浓度之间隔着边界层高度、垂直分布等一系列变量,这也是后面要做降尺度的原因。我用数据时最怕看到有人把卫星柱浓度直接当近地面浓度用,单位都对不上,分析结果自然跑偏。
2.2 柱浓度到近地面浓度:一场降尺度接力
高分辨率近地面SO2浓度产品的核心难点,就是把紫外反演的对流层柱浓度“翻译”成地面上方便人类呼吸层的数据,同时把空间分辨率从卫星原始像素的十几公里甚至几十公里,细化到几公里甚至更细的规则网格。现在业内主流方案是“卫星柱浓度+气象再分析+地理辅助变量+机器学习模型”。
具体来说,模型特征通常包括对流层SO2柱浓度、边界层高度、温度、湿度、风速、气压这些大气变量,再叠上海拔、人口密度、土地利用类型、植被指数等地理特征。训练标签就是地面国控站点的实测SO2浓度。模型在站点位置上学习“柱浓度、气象、地理条件”和“地面浓度”之间的非线性映射,然后把学到的规律推广到全国每一个网格。
这个方案能跑通的关键,在于2013年之后国控监测站点数量足够多、空间分布足够广,机器学习的训练样本才够丰富。常见模型包括随机森林、梯度提升树、深度神经网络,不同团队会做不同变体,但底层逻辑是一致的。我自己测试过不同模型的效果,梯度提升类模型在SO2这种强非线性关系上表现通常很稳,收敛快、不容易过拟合,特征重要性还能帮你看出哪些变量在主导浓度变化。
日度产品是模型对每一天、每一个网格独立预测得到的,月度产品则是对日度结果做时间聚合。有些方案在月度聚合时会再做一步平滑或融合校正,这会让月度数据的空间连续性和年际稳定性更好。理解了这个生成流程,你就知道为什么月度产品比日度产品稳,也理解为什么做趋势分析时不该直接用日度数据硬算。
2.3 质量控制里那些容易被忽略的细节
数据处理流程里,质量控制是最枯燥但最要命的一环。卫星原始反演结果绝不可能直接进网格,中间至少要过三道关卡。
第一道是云筛选。紫外反演在晴空条件下最好用,云量高的像元信号污染严重,通常直接剔除。这样一来日度产品的空间覆盖就打折扣,这也是为什么你打开某一天的数据会发现大片NaN。第二道是轨道异常剔除,部分卫星传感器的紫外探测器会随着在轨时间出现坏行或退化像素,这些像元反演出来的数据是系统性偏高的,必须标记剔除。第三道是极端事件识别。火山喷发会把区域SO2柱浓度抬高几个数量级,大型工业事故也会造成局部极端高值,如果不做识别和处理,这些异常值会被模型误当成真实分布去学习,做出来的网格产品在完全无关的区域也会出现诡异高值。
质量控制做完,才算拿到干净的柱浓度场。再往后才是边界层订正、湿度订正、机器学习降尺度这一串流程。我每次拿到一份新的SO2产品,第一件事就是看它的质量控制文档,搞清楚缺失值是怎么来的、边界层假设是什么、极端事件怎么处理的,这三件事直接决定数据能不能用于我的分析场景。
3. 一个月/日度SO2数据的完整实操路径
3.1 拿到NetCDF先别跑:三步看懂数据结构
这套数据集最常见的格式是NetCDF4,后缀通常是.nc。很多新手第一件事就是写代码打开文件,我的建议是先花两分钟看元数据,磨刀不误砍柴工。
第一步,用xarray打开数据后先打印全局属性,搞清楚地名投影、网格定义、时间单位。变量名一般叫SO2或者SO2_conc,但不同版本可能叫col_SO2(柱浓度)或者surf_SO2(近地面浓度),这个区别必须搞清楚。第二步,看单位。近地面浓度通常用μg/m³,柱浓度用DU,一旦看到DU那就千万别拿去做呼吸暴露评估。第三步,看维度顺序和缺失值情况。
python复制import xarray as xr
ds = xr.open_dataset("SO2_monthly_2013_2023.nc")
print(ds)
print(ds["SO2"].attrs)
打印出来之后,确认维度是不是(time, lat, lon),经纬度范围是不是覆盖全国,时间步长是不是从2013-01到2023-12。这些检查两分钟就能做完,但能省掉后面80%的麻烦。
3.2 城市时间序列提取 + 批量处理技巧
做城市级分析最常见的需求,是提取某个城市的SO2时间序列。最稳妥的办法不是取站点所在那个单一网格,而是以城市中心为圆心、取一个小半径范围内的网格均值,这样能平滑单网格的噪声。
python复制def extract_city_series(ds, lon0, lat0, radius=0.1):
da = ds["SO2"]
mask = ((da.lon - lon0) ** 2 + (da.lat - lat0) ** 2) <= radius ** 2
subset = da.where(mask, drop=True)
return subset.mean(dim=["lat", "lon"])
这里有个小提醒:用经纬度欧氏距离做圆半径,在中低纬度地区问题不大,到高纬度地区经线会明显收敛,最好先乘上cos(latitude)做距离校正,或者改用按实际行列号索引规则网格。处理多个城市时,把城市列表存成DataFrame,循环调用这个函数,结果存成二维表,一列时间、一列一个城市,方便后续绘图和分析。
提取出来的序列,我一般会顺手画一张时间序列图看看形态,先观察有没有诡异的跳变和缺失段,再决定要不要做进一步处理。人眼对异常值的判断有时候比任何统计检验都快。
3.3 十年趋势怎么算:从年际均值到显著性检验
算十年趋势是SO2数据集最常见的应用,但方法上用错了很常见。最基本的做法是把月度数据聚合成年度均值,然后做线性回归看斜率。这个做法能看出大方向,但统计严谨性不足,因为大气浓度时间序列存在明显自相关,普通线性回归会低估标准误,导致显著性检验偏乐观。
更稳妥的做法是用Theil-Sen斜率估计配合Mann-Kendall检验。Theil-Sen对异常值不敏感,Mann-Kendall是一种非参数趋势检验方法,不要求数据服从正态分布,非常适合环境浓度这类长尾数据。pymannkendall这个库封装得很干净,几行代码就能跑完。
python复制import pymannkendall as mk
import pandas as pd
# series 是 Pandas Series,索引为年份,值为年均SO2浓度
trend = mk.original_test(series)
print(trend.slope) # 年变化斜率
print(trend.p) # p值
不过我更建议把趋势分析拆成冷季和暖季分别做。SO2的排放结构和气象条件有明显的季节差异,采暖季受散煤燃烧影响大,暖季主要受工业排放和光化学反应影响。合并成一个年均值,两个信号会互相抵消,看不出治理措施到底作用在哪个季节。用月度数据把12月、1月、2月定义为冷季,6月、7月、8月定义为暖季,分别计算季节均值再跑趋势检验,能讲出来的故事丰富得多。
3.4 和国控站点对比验证的正确姿势
拿卫星网格产品和地面监测站对比,是所有验证工作的标准动作,但操作细节里全是坑。
时间是第一关。国控站点公布的是小时值,通常需要聚合到日均值或月均值再和网格数据对齐。时间尺度不匹配会让对比结果出现虚假偏差,尤其在冬季污染过程期间,日内浓度波动剧烈,小时值和日均值根本没有可比性。
空间匹配是第二关。不要直接拿站点坐标去索引网格,先搞清楚网格的左下角对齐还是中心对齐。常见的设计是格点坐标代表网格中心,但你拿到手的产品不一定按这个规则写。稳妥办法是把站点坐标换算成行列号,再取对应的网格值;如果担心单网格噪声,可以取站点周围3×3网格的平均值,这在空间代表性上更合理。
验证指标要成套看,R²看相关、RMSE看误差大小、斜率看系统偏差、相对偏差看方向。一套指标看全了,才能判断产品在你关心的区域和时间段到底行不行。
4. 从数据看十年:SO2浓度变化背后藏着的信号
4.1 采暖季高峰被“削平”的过程,比想象中清晰
拿着这套数据我第一次认真看全国月均SO2长期序列时,最直观的感受就是:采暖季高峰被“削平”的过程,清晰得让人意外。
2013到2015年,华北很多城市的月度序列有一个非常醒目的冬季峰,12月和1月的浓度能比夏季高出两到三倍甚至更多,一眼就能看出是采暖季散煤燃烧叠加冬季不利气象条件的排放高峰。到了2017年到2019年这段,这个冬季峰的幅度开始明显收窄,煤改气、煤改电和散煤治理对一次燃煤型污染物的削减效果,在月度曲线上体现得非常直接。到2021年之后,不少城市冬季和夏季的SO2浓度差异已经很小,月度曲线的季节形状从一个“尖峰”逐步变成一个“小鼓包”。
把握住这个演化过程,你就会意识到SO2数据的价值绝不仅仅是描述污染本身,它是观察能源结构转型的一根灵敏探针。SO2和PM2.5不同,PM2.5还有大量二次生成成分,SO2的主要来源就是燃煤和工业过程,来源相对单一,排放变化和政策行动之间的对应关系更加直接。
4.2 2020年和2022年的两次异常低值,怎么解读
看日度数据时,2020年有一段特别显眼的异常低值。年初那段排放骤减时期,多个城市的SO2浓度掉到历史极低水平,几乎贴着设备检出限走。但有意思的是,排放管控缓和之后,浓度很快就开始回弹,夏季基本恢复到往年同期水平。
这说明什么?说明这次低值是短期活动强度下降造成的排放中断,不是结构性减排成果。如果只看年度平均,2020年被这次的异常低值拉低了一截,可能会被误读成治理成效的加速显现。把月度或日度序列打开看,才能把这个短期脉冲和长期趋势拆开,避免政策评估的误判。2022年也出现过类似阶段性的低值,同样是活动水平变化主导,并非排放治理能力发生了突变。
这种解读能力,恰恰体现了多时间分辨率数据的价值。如果只有年度数据,你只能看到一个“又降了”的结果,却不知道是怎么降的、降得是否可持续。
4.3 低浓度平台期:SO2变了,研究问题也得跟着变
到2021到2023年,全国大部分城市SO2年均浓度已经压到很低的水平,很多地区全年都没有超过国家环境空气质量标准的那一天。浓度进入平台期之后,数值绝对变化很小,但相对波动反而显眼了。
这个阶段做趋势分析要格外小心。基数变小,同一单位的变化量对应的百分比波动变大,一个仅影响零点几微克每立方米的短期事件,在相对变化率上可能被放大成“显著上升”。我见过一些报告拿这个平台期的数据做年际对比,得出“SO2浓度反弹”的结论,仔细一查就是气象条件差异造成的扰动,不是排放反弹。平台期应该把注意力从趋势检验转移到极端事件识别和与其他污染物的协同分析上。
比如把SO2和PM2.5放在一起看,早期重污染事件中硫酸盐是PM2.5的绝对主力,SO2高值往往领先于PM2.5爆发。随着SO2大幅下降,冬季重污染过程里硝酸盐的贡献占比反而上升。这种污染物结构的此消彼长,是理解近十年空气质量变化的重要线索,也提醒研究者只盯单一污染物会漏掉系统性信息。
4.4 月尺度数据在政策评估里的实操价值
做政策评估时我习惯用月度数据画“逐年同月对比图”。比如把每年1月、2月、12月的区域平均SO2浓度放在同一张图里,叠加成逐年变化的柱状图。这种图比满屏的时间序列曲线更直观,一眼就能看出采暖季削减的节奏。
季度统计也能看出很多端倪。政策执行严格、措施落地快的地区,冷季降幅通常大于暖季;减排偏重末端治理、能源结构未动的情况下,降幅则可能各季差不多。这套数据能精确到月,可以评估“哪一年的哪个月开始出现拐点”,比笼统地说“2017年后下降”要精细得多。配合气象数据做气象调整,还能把浓度变化里气象条件的贡献和排放变化的贡献拆开,了解减排的真正成效。不过气象调整的模型复杂度较高,做之前建议先弄清自己的问题边界。
5. 避坑与验证:我踩过的坑,捡出来给你
5.1 柱浓度与近地面浓度:别让单位骗了你
这个坑我见过太多次了,包括一些已经发表的论文。卫星直接反演给出的是对流层柱浓度,单位是DU,代表气柱总量;近地面浓度产品单位是μg/m³。两者完全不同维度的物理量,柱浓度高不代表地面浓度一定高,因为还要看污染物集中在边界层还是高层。
拿到数据集先看变量属性,凡是变量名带column、col_、DU单位,一律先确认清楚。如果是近地面浓度产品,也要看它的换算假定——有些产品是直接把柱浓度除以边界层高度再换算成体积混合比的,边界层高度假定不同,数值就有系统差异。不同版本的产品之间横向对比之前,先确认单位、变量定义、坐标体系完全一致,否则对比结论没有意义。
5.2 冬季数据的可信度,远比你想象的脆弱
冬季恰好是SO2浓度最高、最该关注的时候,但卫星紫外反演在冬季恰恰是最弱的。冬季太阳高度角低,紫外波段信号弱,反演信噪比下降;加上云量大、边界层低,反演算法对近地面SO2的敏感度进一步降低。
我实测下来的经验是:冬季日度数据的缺失比例明显高于夏季,个别高纬度或云量大的地区,一个月能有效反演的天数可能不到一半。这时候的月度值虽然比日度值稳定,但仍然会有偏低的倾向。做冬季数据分析时,建议先把缺失率统计出来,如果某个月有效像元占比低于30%,这个月的数值就要批量打一个问号。宁可少用一点数据,也不要把它当成高可靠度数值写进论文。拿冬季重污染个例做分析时,用三日滑动平均比直接看单日干净得多。
5.3 缺失值插补:小心补出来的“规律”
日度产品的NaN很常见,某些季节空间覆盖残缺得厉害,很多人的第一反应就是插补。线性插值不是不能用,但只适合连续缺失一两天的情况。SO2浓度受排放和气象驱动,短时段内变化有一定连续性,一两天的插补问题不大。
一旦缺失超过一周甚至更久,简单插值就会制造假规律。比如冬季一次重污染过程期间卫星正好被云挡住,数据全缺,按前后几天线性插值,会把这次过程平滑成不存在,或者插出一个不真实的中间值。更好的选择是用气象特征配合机器学习模型做缺失重建,或者直接用月均值做粗粒度分析,又或者用能处理缺失值的统计模型,而不是强行在日尺度上补全。数据缺了就承认缺了,在方法上留一个透明度,比硬补出来的漂亮序列有价值。
5.4 验证指标要看成套:R²、RMSE、斜率一个都不能少
很多人看模型验证只看R²,R²高就觉得产品好用。实际上R²代表的是相关性,不代表性准确。你完全可以模拟出一条趋势一致但整体平移的序列,R²极高但RMSE也极高,系统性偏差非常大。正确的做法是R²、RMSE、MAE、回归斜率、相对偏差一起看,回归斜率越接近1说明系统偏差越小,RMSE的量级你得心里有数,才知道产品的误差水平能否支撑你的研究结论。
另外还要分清楚验证样本来自训练期内还是时间外。训练期内的交叉验证由于模型见过这些站点,R²天然偏高,只能反映模型的拟合能力;时间外验证,也就是模型没见过的时段,才能真正反映泛化能力。使用产品前,如果文档里说明做过时间外验证,并给出了验证指标,优先看那个指标。
5.5 网格数据和站点数据对不上?先想想空间代表性
拿网格产品和国控站点对比,经常会出现网格值系统性低于站点值的情况。这不一定是产品有问题,很可能是空间代表性差异。
国控站点大多部署在城市里,周边就是交通、燃煤、工业等排放源密集区,测到的是典型的“城市微环境”浓度。而网格产品给出的是一个平方公里级别甚至更大范围的平均浓度,中心城区的高值被周边郊区稀释,网格值自然比城市站点低。这不是数据错误,是空间尺度不同。对比验证时要么把站点数据也做区域平均,要么接受这种代表性差异并把它写进讨论里。直接把站点观测当成唯一真值,去批产品“测不准”,只会让分析失去说服力。
从我的经验看,网格产品和站点数据差多少,在城区站和郊区站表现完全不同。城区站的差值大,郊区站对齐度好很多。拿到数据先看建筑区和背景区的匹配效果,再决定全区域的验证结论怎么写。环境数据没有绝对的真值,理解每个数据源的代表性,比纠结哪一个更“真”重要得多。
我个人这两年用这套数据最大的体会是,SO2现在受到的关注度不如PM2.5和臭氧,环境管理优先级上也让出了位置,但它依然是理解燃煤强度、能源转型和酸沉降变化的一根灵敏探针。数据不会说谎,但解读数据的人需要足够细心。如果你正要拿这套数据集做分析,建议从月度产品、从华北采暖季这个切口入手,先把趋势和季节循环跑通,再切到日度产品去看极端过程,会顺畅很多。最后再提醒一句,拿到任何环境数据集,第一件事永远是读变量说明和单位,这一步做扎实了,后面能少走一大半弯路。
