简介:这份资源为1982至2024年地级市逐月平均气温数据集,面向气象气候研究、区域经济实证分析及深度学习建模人员,可用于气候特征分析、生态保护评估与长时序趋势研究。数据以地级市名称、月份、平均气温为核心字段,覆盖四十余年逐月记录,便于构建面板数据或时间序列模型。压缩包共13个文件,以xml结构化数据文件为主,辅以rels关系描述文件与vml绘图文件,整体约2.6MB,体积轻便易于加载与二次处理。目前已有186人学习下载,适合需要长时段城市气温基础数据的中高级研究者。读者可据此开展气候分区、气温异常检测、社会经济影响回归等实证工作,也可作为人工智能与深度学习任务中的时序特征输入,快速搭建分析流程并验证模型效果。
1. 从一张 1982-2024 年地级市逐月平均气温表说起
如果你手头只有省级气象站的月报,却要评估某个地级市 2015 年 7 月的高温对用电负荷的影响,第一反应往往是「数据粒度不够」。省级均值会把盆地、山区、沿海的差异抹平,做城市级的归因分析时误差能大到没法用。1982-2024 年地级市逐月平均气温数据解决的正是这个粒度问题:它把全国三百多个地级行政区作为空间单元,把每年 12 个月作为时间单元,拼成一张长表,覆盖四十多年。做能源负荷建模、农业物候分析、城市热岛长期趋势、保险精算里的天气因子,都会用到这种「城市 × 月」的面板结构。它适合两类人:一类是手里已经有城市级社会经济数据、缺气象解释变量的分析师;另一类是拿到原始栅格再分析资料、想自己加工成城市面板的工程人员。下面按「数据从哪来、怎么落到城市、怎么校验、怎么避坑」的顺序讲透。
2. 逐月城市气温面板的数据来源与空间降尺度逻辑
2.1 为什么不能直接拿站点月报求平均
气象站点的分布极不均匀,东部平原站点密集,西部高原几百公里才一个站。如果简单地把落在某地级市范围内的站点月均值做算术平均,会得到两个系统性偏差:一是站点多的城市被少数几个站主导,二是站点稀疏的城市样本量太小、方差被低估。更麻烦的是,站点海拔和城市建成区海拔往往差几百米,直接用站点气温代表全市,山区城市会明显偏低。
常见做法是走「格点再分析 + 行政边界统计」的路线。再分析产品(如 ERA5、CRA-40 这类全球/区域再分析)提供规则经纬网格上的近地面气温,空间连续、时间完整,缺点是原始分辨率偏粗(0.1°~0.25°),直接落到地级市会有代表性误差。所以中间必须做一步降尺度或至少做高程订正,把格点值调整到城市实际地形上。
2.2 从格点到地级市:掩膜统计的四个关键参数
把格点气温聚合到地级市,本质是「用行政边界做掩膜,对掩膜内的格点做统计」。这一步有四个参数决定结果质量:
| 参数 | 含义 | 常见取值 | 影响 |
|---|---|---|---|
| 网格分辨率 | 再分析原始或降尺度后格距 | 0.1°≈11km | 越细越贴近城市,但计算量上升 |
| 面积权重 | 格点与市域重叠面积占比 | 按重叠比例加权 | 避免边界格点被整格计入 |
| 高程订正 | 格点高程与市域平均高程差 | 递减率 0.6℃/100m | 山区城市必须做 |
| 缺测处理 | 格点缺测时的填充策略 | 邻域插值或标记 | 直接影响长序列连续性 |
面积权重是最容易被忽略的一项。一个格点可能只有 30% 落在目标市域内,如果按整格计入,边界城市的月均值会被邻市气候「污染」。正确做法是用矢量边界与格网求交,算出每个格点的重叠面积占比,再做加权平均。
2.3 用 Python 把格点月气温聚合成城市面板
下面这段代码演示核心流程:读格点月气温、读地级市边界、做面积加权统计。依赖xarray、geopandas、regionmask或rasterio这类库。
import xarray as xr import geopandas as gpd import numpy as np import regionmask # 1. 读取格点月气温,假设维度为 (time, lat, lon) ds = xr.open_dataset("monthly_t2m_1982_2024.nc") t2m = ds["t2m"] - 273.15 # 开尔文转摄氏度 # 2. 读取地级市边界,字段 city_id 为行政区代码 cities = gpd.read_file("prefecture_boundaries.shp") cities = cities.to_crs("EPSG:4326") # 3. 用 regionmask 把格点分配到城市,numbers 为城市索引 region = regionmask.from_geopandas(cities, names="city_name", abbrevs="city_id") mask = region.mask(t2m, lon_name="lon", lat_name="lat") # 4. 面积加权:cos(lat) 近似格点面积权重 weights = np.cos(np.deg2rad(t2m["lat"])) weights = weights.broadcast_like(t2m.isel(time=0)) # 5. 按城市分组求加权月均值 def weighted_mean(group): w = weights.where(mask == group.name) return group.weighted(w.fillna(0)).mean(dim=["lat", "lon"]) city_month = t2m.groupby(mask).map(weighted_mean) city_month.to_netcdf("city_monthly_t2m.nc")逻辑说明:第 3 步的region.mask会把每个格点标记为所属城市编号,落在多个城市边界上的格点默认归给重叠面积最大的那个,这一步已经隐含了面积归属。第 4 步用纬度余弦做权重,是因为经纬网格在高纬度地区格点实际面积更小,不加权会让北方城市被高估。第 5 步的weighted是 xarray 自带的加权平均,fillna(0)保证海洋或境外格点权重为零、不参与统计。
参数说明:t2m单位务必确认,再分析产品常用开尔文;mask里 NaN 表示不属于任何城市,统计时要排除;如果城市数量超过几百个,groupby().map()会偏慢,可以改用region.mask_3D生成三维掩膜后一次性做矩阵运算。
2.4 高程订正怎么做才不引入新偏差
格点气温对应的是格点平均高程,而地级市平均高程可能差几百米。订正公式是T_city = T_grid + lapse * (Z_city - Z_grid),其中lapse取 -0.6℃/100m。这里有两个坑:一是Z_city要用市域内人口或面积加权的高程,而不是最高峰;二是lapse在冬季和夏季、干湿地区并不恒定,严格做法是按月、按区域标定递减率。如果只是做趋势分析而非绝对温度,订正与否对斜率影响不大,但对城市间横向对比影响显著。
3. 长序列拼接与缺测处理:1982 到 2024 怎么接得上
3.1 不同再分析产品的时间覆盖差异
1982-2024 这四十三年,单一再分析产品未必全程覆盖,或者早期版本与晚期版本存在系统偏差。常见做法是选一个长序列产品为主,用另一个产品做交叉验证,而不是简单拼接。如果必须拼接,要在重叠期做偏差订正:计算两套产品在 1990-2000 年重叠段的月均值差,把这个差值加到早期或晚期序列上,保证接缝处没有跳变。
判断接缝是否处理干净,最直接的办法是画全国平均的月气温时间序列,看拼接年份附近有没有台阶。有台阶就说明偏差订正没做或做反了。
3.2 缺测格点的三种填充策略与适用场景
再分析产品本身缺测少,但降尺度或掩膜过程会产生缺测。三种策略:
- 邻域插值:用周围有效格点反距离加权填充,适合缺测零星、空间连续性强的情况。
- 气候态填充:用该格点多年同月均值替代,适合缺测成片但只关心异常值的场景,缺点是会压低方差。
- 标记不填充:保留 NaN,在后续统计时按有效样本计算,适合缺测比例低、不想引入人造值的严谨分析。
我一般会先统计每个城市每年的有效月数,低于 10 个月的年份直接标记为不可用,而不是硬填。因为逐月数据一旦填充过多,做季节分析时相位会被扭曲。
3.3 用 pandas 做城市面板的缺测体检
import pandas as pd # 读入长表:columns = [city_id, year, month, t2m] df = pd.read_csv("city_monthly_t2m.csv") # 1. 每年每城有效月数 valid = df.dropna(subset=["t2m"]).groupby(["city_id", "year"]).size() valid = valid.rename("valid_months").reset_index() # 2. 标记不完整年份 valid["usable"] = valid["valid_months"] >= 10 # 3. 统计每个城市不可用年份占比 bad_ratio = valid.groupby("city_id")["usable"].apply(lambda s: 1 - s.mean()) print(bad_ratio.sort_values(ascending=False).head(10))逻辑说明:第 1 步先剔除气温缺失的记录再计数,避免把 NaN 当成有效月。第 2 步用 10 个月作为阈值,是因为缺 3 个月以上时年均值代表性明显下降。第 3 步输出不可用比例最高的城市,这些城市要么边界特殊、要么格点覆盖差,后续分析要单独说明。
参数说明:阈值 10 不是硬标准,做生长季分析可以放宽到 8,做年际变率分析建议收紧到 11。city_id要保证跨年份一致,行政区划调整导致的代码变更需要提前做映射。
3.4 行政区划变更带来的「同名不同界」问题
1982 年以来,很多地级市经历过撤地设市、边界调整、更名。如果直接用当前边界去统计历史格点,会出现「现在的市域范围套在 1982 年的气温场上」,空间代表性有偏差。严谨做法是使用逐年行政区划矢量,或者至少对发生过重大边界调整的城市做备注。做长趋势分析时,边界变化会引入虚假的突变,这一点在论文和报告里必须交代。
4. 避坑与排查:城市气温面板最容易翻车的五个地方
4.1 现象:某城市月均值明显高于周边 → 原因:格点归属错误 → 解决:检查掩膜
如果发现某个城市的 7 月气温比邻市高 3℃以上,先怀疑掩膜。常见原因是边界矢量坐标系不是 WGS84,或者格点经度范围是 0-360 而边界是 -180-180,导致掩膜错位。把两者画在同一张图上目视检查,是最快的排查手段。
4.2 现象:冬季城市间差异异常小 → 原因:高程订正缺失 → 解决:补递减率
冬季逆温和高程效应叠加,山区城市应该明显更冷。如果所有城市冬季气温挤在一起,多半是没做高程订正,格点平均高程把地形差异抹平了。补上lapse订正后,山区城市的冬季月均值会下移。
4.3 现象:时间序列在拼接年出现台阶 → 原因:产品间系统偏差 → 解决:重叠期订正
拼接两套再分析产品时,如果不做偏差订正,接缝处会出现 0.5~1.5℃ 的跳变。排查方法是画全国或区域平均的月气温序列,台阶肉眼可见。解决是在重叠期计算逐月偏差,加到其中一套上。
4.4 现象:某年整片区域缺测 → 原因:原始产品该时段异常 → 解决:查产品文档并标记
再分析产品偶有整段异常,表现为某年某区域全为 NaN 或常数。不要急着插值,先查产品发布说明,确认是已知问题还是下载损坏。如果是已知问题,在数据里加质量标记,分析时排除该年。
4.5 现象:城市年均值方差偏小 → 原因:缺测填充过度 → 解决:改用有效样本统计
用气候态填充大量缺测后,序列方差会被压缩,做极端值分析时低估风险。排查方法是比较填充前后同城市的方差。如果差异超过 20%,说明填充比例过高,应改为按有效月统计或直接标记不可用。
5. 从月均值到可用指标:派生变量与验证技巧
拿到逐月平均气温只是起点,真正进模型前通常要派生几个指标。第一个是距平,用T - T_clim,其中T_clim是该城市该月 1982-2024 的多年均值,距平能去掉城市间气候差异,直接反映异常。第二个是季节均值,按 3-5、6-8、9-11、12-2 分组,注意冬季跨年要按气象季节把 12 月归到次年。第三个是趋势斜率,对每个城市每个月的序列做 Theil-Sen 或线性回归,得到 43 年的升温速率。
验证方面,我习惯做两件事。一是和公开的省级统计年鉴月气温做对比,看城市聚合到省之后的偏差是否在 ±0.5℃ 以内,超出就回头查掩膜和权重。二是做空间一致性检查,用莫兰指数或简单的邻域差分,看是否存在孤立的异常城市,孤立异常多半是数据问题而非真实气候信号。
from scipy.stats import theilslopes # 对每个城市每月计算 Theil-Sen 斜率 def slope(series): years = series.index.get_level_values("year").values return theilslopes(series.values, years)[0] trend = (df.dropna(subset=["t2m"]) .set_index(["city_id", "month", "year"])["t2m"] .groupby(["city_id", "month"]) .apply(slope) .rename("trend_per_year"))逻辑说明:theilslopes返回中位数斜率,对异常值比最小二乘稳健。按city_id和month分组,得到每个城市每个月的升温速率,单位是 ℃/年。参数说明:序列长度不足 20 年时斜率不可靠,建议过滤;years要用实际年份而非序号,避免缺年导致斜率偏移。
最后说个我自己的习惯:每次拿到新的城市气温面板,先画三张图——全国城市年均温的空间分布、几个代表城市的月气温气候态曲线、全国平均的距平序列。这三张图能在一小时内暴露九成以上的数据问题。做数据这行,后悔药很少,前置检查做足比事后返工划算得多。希望帮到你。
本文还有配套的精品资源,点击获取