全球柯本气候区划shp数据空间分析实战:Python与PostGIS叠加应用 简介全球柯本气候区划SHP数据面向地理学、环境科学、气候研究及城乡规划等领域的科研人员与GIS学习者用于分析地球表面气候类型分布及其与行政区划、生态系统的空间关系。资源包共43个文件约7.15MB以Shapefile矢量数据为核心包含shp几何边界、shx空间索引、dbf属性表、prj投影信息等同时附带tif栅格图、mxd地图文档、lyr图层文件、lpk打包文件及xls站点信息表兼顾矢量与栅格两种使用方式。柯本分类依据年均温、最热与最冷月均温及降水季节性将全球气候划分为热带、干燥、暖温带、寒冷和极地五大类并细分亚类属性表可提取气候代码与名称。已有2409人学习下载读者可借助GIS软件将气候区划与行政边界、地形、人口等图层叠加开展空间分析与制图为农业生产布局、水资源管理和气候变化适应策略提供数据支撑。1. 全球柯本气候区划 shp 数据一份被低估的空间分析底图做空间分析的人迟早会撞上一个需求把气候条件作为变量叠加到业务图层上。农业区划要看积温带光伏选址要看辐照与云量物流时效分析要避开极端降水区甚至连连锁门店的选址模型都想加一个「气候舒适度」权重。这时候你需要的不是一张花花绿绿的全球气候类型图而是一份带属性表、能按字段筛选、能直接做空间连接的矢量数据——全球柯本气候区划 shp 数据就是干这个的。柯本气候分类本身不复杂它用气温和降水两个维度把全球划成 A热带、B干旱、C温带、D冷温带、E极地五大类再往下细分出 30 来个子类型。真正让它在工程里好用起来的是这份数据被整理成了标准 shp 格式每个多边形带一个气候代码字段你可以在 QGIS 或 PostGIS 里直接WHERE climate_code LIKE Cfa%把亚热带湿润区捞出来。适合谁用做遥感反演验证的、做物种分布模型的、做气候风险评估的以及所有需要「给地球表面贴标签」的人。2. 柯本气候区划 shp 数据的字段结构与选型逻辑2.1 属性表里到底有什么从气候代码到分类层级拿到一份柯本 shp第一件事不是画图是打开属性表看字段。常见的字段设计有两种流派一种是扁平式直接给一个climate字段存完整代码比如Cfa、BWh、Dfb另一种是层级式拆成main_cls主类、sub_cls子类、precip_type降水型、temp_type温度型四个字段。层级式对做统计聚合更友好比如你想算「所有干旱区占全球陆地面积的比例」直接GROUP BY main_cls就行不用写一堆LIKE B%。我一般会先跑一段 Python 把字段结构摸清楚顺便检查有没有空值或编码乱码。下面这段代码用geopandas读 shp输出字段名、类型、唯一值数量和前几行样本import geopandas as gpd # 读取柯本气候区划 shp注意指定编码老数据常用 latin1 或 utf-8 gdf gpd.read_file(koppen_global.shp, encodingutf-8) # 打印字段名和数据类型 print(字段列表) print(gdf.dtypes) # 对每个字段统计唯一值数量判断是分类字段还是连续字段 for col in gdf.columns: if col ! geometry: nunique gdf[col].nunique() print(f{col}: {nunique} 个唯一值) # 查看气候代码字段的取值分布 if climate in gdf.columns: print(gdf[climate].value_counts().head(10)) # 检查几何有效性避免后续空间连接报错 invalid gdf[~gdf.geometry.is_valid] print(f无效几何数量{len(invalid)})这段代码的逻辑很直白先看字段类型object通常是字符串分类字段float64可能是面积或温度数值再看唯一值数量如果某个字段只有 5 个唯一值那它大概率是主类字段。最后检查几何有效性是血泪经验——有些从栅格转出来的 shp 会带自相交多边形直接做sjoin会报拓扑异常提前用is_valid筛出来能省很多排查时间。参数方面encoding这个参数别省。柯本数据很多是从欧洲或北美的老数据集转过来的属性表里带重音符号的拉丁字符如果编码不对读出来就是乱码后面按字段筛选全废。如果utf-8读出来还是乱试试latin1或cp1252。2.2 为什么选 shp 而不是 GeoTIFF 或 GeoJSON这里要讲清楚选型理由不然你会在错误的方向上浪费很多时间。柯本气候区划的原始产物通常是栅格GeoTIFF分辨率从 0.5° 到 1km 不等。栅格的好处是计算快、适合做像元级统计坏处是边界锯齿化严重而且属性信息藏在栅格值里你想按气候类型做矢量叠加分析时非常别扭。shp 的优势在于第一多边形边界是平滑的出图好看做报告直接能用第二属性表是结构化的可以跟行政区划、土壤类型、土地利用等矢量数据做空间连接第三在 PostGIS 里可以建空间索引百万级多边形的查询也能秒回。GeoJSON 虽然也是矢量但文件体积大、没有空间索引、字段类型支持弱适合做 Web 展示不适合做分析底图。代价是什么shp 的多边形数量可能很大。全球 1km 分辨率的柯本数据转成矢量后多边形数量轻松上百万单个 shp 文件可能好几个 GB。这时候你需要做简化simplify或者按大洲拆分。我一般会先按主类拆成 5 个 shp用的时候只加载需要的那个内存压力小很多。# 按主类拆分减少单文件体积 for cls in gdf[main_cls].unique(): subset gdf[gdf[main_cls] cls] subset.to_file(fkoppen_{cls}.shp, encodingutf-8) print(f{cls}: {len(subset)} 个多边形)拆分之后每个文件通常能控制在几百 MB 以内QGIS 打开不卡Python 读取也快。注意to_file的时候如果字段名超过 10 个字符shp 格式会截断这是 shp 的老毛病提前把字段名改短。3. 用 Python 做柯本气候区划的空间叠加分析3.1 环境准备与依赖版本做空间分析最怕环境问题。geopandas、shapely、fiona、pyproj这四个库的版本兼容性是个玄学版本对不上就是各种ImportError或CRS mismatch。我一般用 conda 建独立环境别在 base 环境里折腾conda create -n koppen python3.10 conda activate koppen conda install -c conda-forge geopandas shapely fiona pyproj rtree用conda-forge渠道装二进制依赖会自动处理好。rtree是空间索引库做sjoin的时候如果没有它会退化成暴力遍历速度差几十倍。装完之后跑一句gpd.__version__确认能正常导入。3.2 把气候区划叠加到业务图层以农业网格为例假设你有一份农业监测网格比如 10km 分辨率的格点想给每个格点标上气候类型。核心操作是空间连接spatial join用格点的几何去跟柯本多边形求交集。下面这段代码演示完整流程import geopandas as gpd import pandas as pd # 读取柯本气候区划只保留需要的字段 koppen gpd.read_file(koppen_global.shp, encodingutf-8) koppen koppen[[climate, main_cls, geometry]] # 读取农业网格点数据 grid gpd.read_file(agri_grid.shp, encodingutf-8) # 统一坐标系柯本数据常见是 EPSG:4326网格如果是投影坐标系需要转 if koppen.crs ! grid.crs: grid grid.to_crs(koppen.crs) # 空间连接每个格点落在哪个气候多边形里 joined gpd.sjoin(grid, koppen, howleft, predicatewithin) # 检查有多少格点没匹配上气候区 unmatched joined[joined[climate].isna()] print(f未匹配格点数{len(unmatched)}) # 按气候类型统计格点数量 stats joined.groupby(climate).size().reset_index(namegrid_count) print(stats.sort_values(grid_count, ascendingFalse).head(10)) # 导出结果 joined.to_file(grid_with_climate.shp, encodingutf-8)逻辑说明sjoin的predicate参数决定空间关系within表示格点完全落在多边形内部。如果格点刚好在边界上within可能匹配不上这时候改用intersects会更宽松但可能一个格点匹配到多个气候区需要后续去重。howleft保证所有格点都保留没匹配上的气候字段为NaN方便你排查是数据范围问题还是坐标系问题。参数方面predicate的选择直接影响结果within严格、intersects宽松、contains方向相反。做气候叠加我一般用within因为气候区边界本身有过渡带格点落在边界上的情况很少严格一点反而干净。如果发现未匹配格点集中在海岸线附近那多半是柯本数据本身不覆盖海洋属于正常现象。3.3 面积统计与气候类型占比计算另一个高频需求是算面积。柯本 shp 在 EPSG:4326 下直接算面积得到的是平方度没有物理意义。必须先投影到等面积坐标系比如 Mollweide 或 Equal Earth再算面积。# 投影到等面积坐标系 koppen_equal koppen.to_crs(projeqearth datumWGS84) # 计算每个多边形的面积平方公里 koppen_equal[area_km2] koppen_equal.geometry.area / 1e6 # 按主类汇总面积 area_by_class koppen_equal.groupby(main_cls)[area_km2].sum() area_by_class area_by_class.sort_values(ascendingFalse) print(area_by_class) # 计算占比 total_area area_by_class.sum() area_by_class_pct (area_by_class / total_area * 100).round(2) print(area_by_class_pct)这里的关键是投影选择。Equal Earth 投影是近几年比较推荐的全球等面积投影形状变形比 Mollweide 小。area属性返回的是投影平面上的面积单位是平方米除以1e6转成平方公里。注意to_crs会重新计算几何如果数据量很大百万级多边形这一步可能耗时几分钟建议先按大洲裁剪再投影。4. 柯本气候区划数据处理的避坑与排查4.1 坐标系不统一导致空间连接全空现象sjoin跑完发现所有气候字段都是NaN但两份数据的范围看起来都在全球。原因一份是 EPSG:4326经纬度另一份是 EPSG:3857Web 墨卡托虽然画出来位置差不多但坐标数值差了几个数量级空间索引根本匹配不上。解决连接前先print(gdf.crs)确认不一致就to_crs统一。别信「看起来对」这种直觉坐标系是黑匣子必须显式检查。4.2 多边形自相交导致拓扑异常现象sjoin或overlay报TopologyException: found non-noded intersection。原因从栅格转矢量时边界像元可能生成自相交或重叠的多边形。解决用shapely的buffer(0)做零宽缓冲修复或者用make_validfrom shapely.validation import make_valid gdf[geometry] gdf.geometry.apply(make_valid)buffer(0)是老方法对大多数自相交有效make_valid是新版 shapely 的推荐做法修复能力更强。修复后重新检查is_valid确认全部通过再往下做。4.3 字段名截断与编码乱码现象写入 shp 后发现字段名变了climate_code变成climate_c或者属性表里中文/特殊字符显示为问号。原因shp 格式的 DBF 表头限制字段名最多 10 个字符且默认编码不支持 Unicode。解决写文件前把字段名改成 10 字符以内的英文缩写编码显式指定encodingutf-8。如果必须保留长字段名考虑输出 GeoPackage.gpkg格式它没有这些限制。4.4 大文件内存溢出现象读取全球 1km 分辨率的柯本 shp 时 Python 进程被 kill或者 QGIS 直接卡死。原因百万级多边形一次性加载进内存普通笔记本扛不住。解决用pyogrio引擎的read_file配合bbox参数做范围过滤只读需要的区域# 只读取东亚范围的多边形 gdf gpd.read_file( koppen_global.shp, bbox(70, 15, 140, 55), # 经度 min, 纬度 min, 经度 max, 纬度 max enginepyogrio )bbox参数在pyogrio引擎下会利用空间索引做过滤比读完再筛快很多。如果数据源没有空间索引先用ogr2ogr建一个。4.5 气候代码大小写不一致现象按climate Cfa筛选结果为空但属性表里明明有cfa。原因不同来源的数据对气候代码的大小写规范不统一有的全大写有的首字母大写。解决筛选前统一转大写koppen[climate] koppen[climate].str.upper().str.strip()strip()是防止前后有空格这种脏数据在手工整理过的 shp 里很常见。做完标准化再筛选能避免很多「明明有数据却查不到」的翻车。5. 进阶技巧用 PostGIS 管理柯本气候区划并做批量空间查询当你的业务数据量到了千万级Python 的geopandas就力不从心了。这时候把柯本 shp 导入 PostGIS用数据库的空间索引和 SQL 做批量查询性能提升是数量级的。下面是我常用的一套流程。第一步用shp2pgsql把 shp 导入 PostGISshp2pgsql -s 4326 -I -D koppen_global.shp public.koppen | psql -h localhost -U postgres -d gisdb-s 4326指定坐标系-I创建空间索引-D用 dump 模式比默认的 insert 模式快。导入后建一个 GIST 索引CREATE INDEX idx_koppen_geom ON koppen USING GIST (geometry);第二步批量查询每个业务点所在的气候区SELECT g.grid_id, k.climate, k.main_cls FROM agri_grid g LEFT JOIN koppen k ON ST_Within(g.geom, k.geometry);ST_Within跟geopandas的within语义一致。PostGIS 会自动走空间索引千万级格点的查询通常几分钟内能跑完。如果还是慢检查EXPLAIN ANALYZE的输出确认走了Index Scan而不是Seq Scan。第三步做气候类型的面积汇总SELECT main_cls, SUM(ST_Area(ST_Transform(geometry, 8857)) / 1e6) AS area_km2 FROM koppen GROUP BY main_cls ORDER BY area_km2 DESC;这里ST_Transform把几何转到 EPSG:8857Equal Earth 投影ST_Area算面积单位是平方米。EPSG:8857 是 PostGIS 内置的等面积投影不用自己拼 proj 字符串。一个我踩过的坑PostGIS 的ST_Within对无效几何同样会报错导入前最好用ST_MakeValid清洗一遍。另外如果柯本数据是多边形集合MultiPolygonST_Within的行为跟单多边形一致不用特殊处理。最后说一个验证方法拿几个已知城市的坐标手动查一下气候类型跟权威分类对一下。比如新加坡应该是 Af热带雨林开罗应该是 BWh热带沙漠莫斯科应该是 Dfb温带大陆性湿润。如果查出来对不上大概率是坐标系或字段映射出了问题。这个习惯帮我省过好几次返工——数据看起来没问题不代表真的没问题。希望帮到你。本文还有配套的精品资源点击获取