
简介面向GIS从业者、地理信息研究人员及区域规划、国际经贸分析等领域用户这份矢量数据集覆盖中亚五国哈萨克斯坦、乌兹别克斯坦、吉尔吉斯斯坦、塔吉克斯坦、土库曼斯坦的基础地理要素以Shapefile格式组织可在ArcGIS、QGIS等主流GIS软件中直接读取编辑适用于地图制图、区域分析、资源调查、边界研究等场景免去自行采集和矢量化底图的繁琐过程。资源以RAR压缩包提供共8个文件约545KB包含.shp几何文件、.shx空间索引、.dbf属性表、.prj坐标系统定义以及.shp.xml元数据、.CPG字符编码等辅助文件各文件分工明确确保数据在不同GIS环境中被正确读取与显示。已有186人学习/下载。用户可获得一套结构标准、可直接投入项目的中亚区域基础空间数据配合属性表中的国名等信息可快速完成专题地图制作、多图层叠加分析、区域对比统计等任务减少重复建模与数据预处理的时间成本服务科研、教学与区域决策支持。1. 中亚五国矢量图shp格式一张行政区划底图从哪里开始做数据可视化、离线地图底图或者跨区域分析时最常遇到的原始数据就是“中亚五国矢量图shp格式”。这类文件表面上是五个国家的行政边界实际拿到手往往分哈萨克斯坦、吉尔吉斯斯坦、塔吉克斯坦、土库曼斯坦、乌兹别克斯坦多个目录摆放后缀是 .shp/.shx/.dbf/.prj。真正项目的卡点不在于“有没有数据”而在于坐标系缺失、字段乱码、边界闭合失败且五个国家的数据口径不一致。这篇文章按我处理这类底图数据的顺序走一遍先检查文件结构再修坐标系和属性编码接着导出 wkt 文本最后抽稀验证得到一份能直接进数据库的干净底图。2. 数据源选型与质量评估shp文件拿到手先做三件事2.1 数据源口径先分清GADM、Natural Earth 还是官方测绘数据很多初学者拿到 shp 就问“哪个版本最新”其实行政区划数据没有绝对的“最新”只有“够不够用”。常见做法是先认清楚三类数据源一类是 GADM 这种全球行政区划数据集优点是省界完整、字段规范适合做省市级分析缺点是部分区域更新滞后局部边界细节和官方公报可能对不上另一类是 Natural Earth 这类制图型数据边界天然带有抽稀适合做宏观底图、小比例尺展示不适合做高精度量算第三类是各国测绘或统计部门发布的官方区划数据精度最高但字段命名五花八门投影方式也多带本地坐标系需要先读元数据。我的经验是五个国家混在一起做分析时优先选 GADM 这类统一来源这样字段结构一致省去逐国对齐字段的麻烦。如果你只是出图、做专题配色Natural Earth 更轻量加载也更快。选型之后最重要的一步不是立刻开始画图而是检查数据是不是真的“干净”。下面用一个最小脚本把文件结构和几何信息一次看完。2.2 用GeoPandas检查shp三件套文件结构、要素数量和字段shp 不是单独一个文件而是由 .shp、.shx、.dbf、.prj 等后缀组成的文件集合。.shp 存几何坐标.shx 是空间索引.dbf 存属性表.prj 存坐标系信息.cpg 存字符编码声明。任何一个文件缺失都会导致读取出问题。先用 -la 检查文件是否齐整ls -la kz_adm1.shp kz_adm1.shx kz_adm1.dbf kz_adm1.prj kz_adm1.cpg如果 .prj 缺失后续 GIS 软件会默认数据是未知坐标系如果 .cpg 缺失中文属性最容易乱码。文件齐整之后再用 GeoPandas 读取并打印基本信息import geopandas as gpd shp_file central_asia/kz_adm1.shp gdf gpd.read_file(shp_file) print(坐标系:, gdf.crs) print(要素数量:, len(gdf)) print(字段列表:, gdf.columns.tolist()) print(范围:, gdf.total_bounds) # [xmin, ymin, xmax, ymax] print(gdf.head(3).to_string())这段代码的用途是快速判断 shp 是否能被正常解析。crs 为 None 意味着坐标系缺失后面所有空间操作都可能翻车要素数量为 0 或者范围明显异常比如经纬度范围超出 -180 到 180说明几何或投影有问题。字段列表用于确认 NAME_0、NAME_1、GID 这类属性列是否齐全有些数据源把国名写成 COUNTRY有的写成 NAME_0不统一的时候需要在后面做字段映射。2.3 质量评估的两个硬指标边界闭合与拓扑重叠检查完文件结构接着看几何质量。shp 的面要素在生成过程中经常出现自相交、重复点、缝隙这类拓扑错误。直接运行 is_valid 统计非法要素数量print(非法几何数量:, (~gdf.geometry.is_valid).sum())对于非法要素最简单的修复手段是 buffer(0)。这个操作会把自相交的环重新整理成合法的 Polygon同时保留原有边界形状是我处理 shp 拓扑问题的首选方案invalid_mask ~gdf.geometry.is_valid if invalid_mask.any(): gdf.loc[invalid_mask, geometry] gdf.loc[invalid_mask].geometry.buffer(0)处理完还需要检查面与面之间是否有重叠或缝隙。血泪经验是两个相邻省份的面如果各自闭合合并时就会留下一条窄缝做空间统计时统计面积会偏小。可以用 unary_union 看一下合并后的总面积和各要素面积如果差值超过半平方公里说明存在重叠或缝隙需要先统一边界再使用。这一步做完这份 shp 才具备当底图的资格。3. 坐标系与投影排查为什么shp打开后“飞”到海里3.1 三个最典型的坐标系病相坐标系问题在中亚五国 shp 数据里几乎绕不开。常见病相有三个第一种是数据在 QGIS / ArcGIS 里打开后图形缩成一个小黑点位置在赤道和本初子午线附近第二种是数据看起来正常但叠加在线底图上后错位数百米到数公里第三种是整个图形被压扁或拉伸成长条方向像被旋转过。这三个病相分别指向三种原因.prj 文件缺失导致坐标系未知、数据本身是 Web 墨卡托投影但被当作经纬度读取、经纬度坐标顺序颠倒。判断方法很简单读取后打印 total_bounds。如果范围是类似[0.0, 0.0, 20037507.0, 20037507.0]这种大数值说明坐标单位是米数据是投影坐标系如果范围是[46.5, 41.0, 87.5, 55.5]这类小数说明坐标单位是度常见于 WGS84 经维度。根据范围就能猜出原始坐标系这是做坐标系修复的前提。3.2 手动补坐标系set_crs 和 to_crs 不能混用很多新手把 set_crs 和 to_crs 当成一回事实际差别很大。set_crs 只是“声明”当前数据是什么坐标系不改变任何坐标值to_crs 才是真正的重投影会重新计算坐标。如果 .prj 缺失但你知道数据源按 WGS84 经纬度发布就先用 set_crs 声明再按需转换# 已知数据本身是 WGS84 经纬度但缺少 .prj 文件 gdf gdf.set_crs(epsg4326) # 如果需要转成 Web 墨卡托或其他投影 gdf_mercator gdf.to_crs(epsg3857)set_crs 之后务必再打印一次 total_bounds确认范围没有发生意外变化。如果范围依然异常比如坐标变成[4600000.0, ...]这类数值说明数据本身就不是经纬度声明 4326 会把数据放到错误位置这时候需要反过来先排查原始投影。3.3 用UTM分带做投影与量算中亚五国横向跨度大哈萨克斯坦东西横跨约 46.5°E 到 87.5°E必须分带处理。日常展示用 4326 就够但做面积统计、长度量算、空间关系判断时我一般会转到 UTM 投影因为经纬度不是等距投影直接用 4326 算面积会产生较大偏差。# 哈萨克斯坦中北部常用 UTM 43NEPSG:32643 gdf_utm gdf_wgs84.to_crs(epsg32643) print(gdf_utm.total_bounds) # X/Y 单位变为米范围约几十万到几百万需要注意五个国家横跨多个 UTM 带不能全程用一个带号算全境面积。常规做法是每个国家按所在带分别投影计算再把结果汇总制图输出则统一转回 4326 或按出图比例尺选择投影。下表是各国大致经度和常用 UTM 带号方便你查参数国家大致经度范围常用 UTM 带EPSG哈萨克斯坦46.5°E - 87.5°E32643 / 32644 / 32645吉尔吉斯斯坦69°E - 80°E32643 / 32644塔吉克斯坦67°E - 75°E32642 / 32643土库曼斯坦52°E - 66°E32640 / 32641 / 32642乌兹别克斯坦56°E - 73°E32641 / 32642 / 326433.4 三个坐标相关的踩坑记录第一坑打开后图形出现在0, 0附近。原因是 .prj 缺失软件默认按未知坐标系展示。解决方法是打印 total_bounds根据坐标数值判断并手动 set_crs再 to_crs 到目标坐标系。第二坑叠加在线底图后错位几百米。原因是 shp 是投影坐标系坐标单位是米却被当作经纬度数据叠加。解决方法是先 set_crs(epsg3857) 或对应投影再 to_crs(epsg4326) 转回经纬度。第三坑图形旋转 90 度呈长条状。原因是经纬度顺序颠倒即把 lat/lon 写成了 lon/lat。解决方法是检查 total_bounds 的 xmin 和 ymin 是否在合理范围如果 x 表示纬度则用坐标交换脚本统一调整或者回到数据源重新确认字段顺序。这类问题在手动爬取或转码的数据中很常见肉眼难以发现务必在早期做范围检查。4. 属性字段与中文编码字段对不上、乱码怎么处理4.1 字段名截断、大小写和连接键中亚五国 shp 的属性表里国家名和行政区名经常出现多种拼写。GADM 的字段一般叫 NAME_0国名和 NAME_1省级名Natural Earth 则多用 ADMIN0NAME官方数据又可能用自己的语言拼写。字段名的差异不算大问题真正麻烦的是 dbf 格式对字段名长度有限制不同软件写入时会截断字段名导致连接时怎么都对不上。我一般不用名称做连接键而是优先查 ISO 3166-1 三字码比如 KZ、KG、TJ、TM、UZ。shp 属性表里如果自带这种编码字段用它做主键最稳定没有的话再建立中文名和英文名的映射表连接前先统一字段名大小写避免 “Name” 和 “NAME” 被当成两个字段。4.2 从dbf探测编码到强制指定中亚五国数据的属性常常混着西里尔字母和拉丁字母编码问题几乎必现。读取时中文乱码通常表现为名称变成“锟斤拷”或“????”。原因是 .dbf 内部字符编码和读取时指定的编码不一致。GeoPandas 读取 shp 时可以强制指定编码常见的有 utf-8、gbk、latin1# 先尝试 utf-8乱码再换 gbk 或 latin1 gdf gpd.read_file(central_asia/kg_adm1.shp, encodingutf-8)如果不知道原文件编码可以用 chardet 探测 .dbf 文件开头几千字节from pathlib import Path import chardet dbf_path Path(central_asia/kg_adm1.dbf) raw dbf_path.read_bytes()[:5000] det chardet.detect(raw) print(det)注意探测结果只代表概率不保证百分之百准确。拿到结果后仍然要做样本检查把打印出的字段值对照原数据判断。项目数据量不大时我直接遍历 utf-8、gbk、latin1 三种编码各读一次用肉眼快速确认哪种最合理效率反而更高。这里没有玄学验证样本是最靠谱的手段。属性字段里还容易混入换行符和首尾空格导致最终导出时字段错位。读取后顺手清理一下for col in gdf.select_dtypes(include[object]).columns: gdf[col] gdf[col].str.replace(\n, ).str.strip()4.3 输出GeoJSON/CSV时的编码选择处理完读取乱码还要注意输出的编码。shp 转 GeoJSON 时GeoPandas 默认输出 UTF-8一般没问题但如果你把属性导出成 CSV 再交给其他程序Excel 打开经常出现乱码。常见做法是导出 CSV 时加 BOM 头或者直接把 CSV 以 utf-8-sig 编码写入gdf.to_csv(kazakhstan_adm1.csv, indexFalse, encodingutf-8-sig)写 shp 文件时如果需要保持中文属性可读可以在 to_file 里指定 encoding 参数。但要注意shp 的 dbf 本身对字符集支持有限跨软件交换数据时优先用 GeoJSON 或 GPKG 代替 shp 作为中间格式。4.4 属性字段乱码排查清单常见问题一是字段全为“????”。原因是 .cpg 文件缺失或错误导致读取时用了错误字符集。解决先尝试 gbk再尝试 latin1配合 chardet 探测。常见问题二是字段名连接不上。原因是两边字段长度截断规则不同、大小写不一致。解决统一转大写或小写用 ISO 编码字段作为关联键。常见问题三是一个国家的省名在另一些国家里显示为空白。原因是源数据本身字段就没填全或者字段名在不同图层里位置不一致。解决读取后用 cols.tolist() 对比两个 shp 的字段按 name_1 列填充缺失值必要时删除空字段不要强求字段一一对应。属性清洗没有太多捷径规范字段名和编码是唯一能长期复用的办法。5. 从shp导出WKT把矢量数据文本化交给数据库和程序5.1 shp转wkt什么时候值得做把 shp 格式矢量数据导出为 wkt最直接的好处是空间数据变成纯文本方便直接写入 PostGIS、SQLite/Spatialite或者作为静态文本文件在程序里做空间判断。wkt 的格式可读性很好POLYGON ((xa ya, xb yb, ...)) 一眼就能看出形状调试接口和写自动化测试时比二进制 shp 好用得多。另一个常见需求是把 wkt 塞进 JSON 或接口返回值里前端地图引擎直接解析省掉后端空间库依赖。代价是 wkt 文本体积比 shp 大要素越多越明显。所以只有做数据交换、入库、调试时我才会导出 wkt如果只是本地分析和渲染直接保留 GeoJSON 或 GPKG 更高效。这个判断按照你后续工作流走即可。5.2 批量转wkt的脚本从shp到csvGeoPandas 读取 shp 后几何对象本身来自 shapely可以直接调用 .wkt 方法获取文本。手动逐行 iterrows 在数据量小时没问题但几百个要素就开始变慢推荐直接在 DataFrame 上生成整列import pandas as pd import geopandas as gpd gdf gpd.read_file(central_asia/uz_adm1.shp) # 批量生成 wkt 列坐标顺序为 x y即经度 纬度 gdf[wkt] gdf.geometry.to_wkt() # 只保留需要的属性列 out gdf[[NAME_0, NAME_1, wkt]].copy() out.to_csv(uz_adm1_wkt.csv, indexFalse, encodingutf-8)参数说明to_wkt 默认不指定精度时会保留完整坐标小数文件偏大如果只是做边界展示可以传入 rounding precision 参数比如 to_wkt(rounding_precision6) 把坐标压缩到小数点后 6 位约 0.1 米精度能明显减小体积。对国家级底图我一般用 rounding_precision5 或 6对省界已经足够。导出的 wkt 文件可以只保留关键属性也可以加一个 id 字段。注意 MultiPolygon 会导出成 MULTIPOLYGON后续入库时要确认字段类型支持PostGIS 和 Spatialite 都原生支持不用额外拆分。5.3 导入SQLite后写空间查询拿到 wkt 文本后最实用的用法是写入本地空间数据库。以 SQLite Spatialite 为例先创建表再把文本转成空间列。这个过程可以用命令行工具或者直接写点小脚本完成核心 SQL 如下CREATE TABLE adm1 ( name0 TEXT, name1 TEXT, geom GEOMETRY ); INSERT INTO adm1 (name0, name1, geom) VALUES ( Uzbekistan, Tashkent, ST_GeomFromText(POLYGON ((69.2 41.3, 69.3 41.3, ...)), 4326) ); -- 空间查询找出哪些省包含某个坐标点 SELECT name1 FROM adm1 WHERE ST_Contains(geom, ST_GeomFromText(POINT(69.24 41.34), 4326));空间查询的好处是把“看地图”变成“查数据”比如判断一个物流点落在哪个州、统计落点在每个国家的数量都可以直接写 SQL不需要发动客户端去手动画图。加载到 PostGIS 时思路一样把 wkt 用 ST_GeomFromText 写入 geometry 字段再加空间索引整体性能和稳定性都优于纯文件操作。6. 最后一步抽稀与验证让五国底图更轻量6.1 保留拓扑的抽稀三个常用容差档国家级底图因为边界形状复杂shp 的体积常常超出预期尤其在网页端加载时卡顿明显。处理方法是抽稀但直接 simplfy 可能把相邻面之间的公共边抽得互相穿透生成狭长三角形缝隙。shapely 2.x 里我一般用 TopologyPreservingSimplifier它在抽稀时尽量维持多边形之间的拓扑关系代价是速度比普通 simplify 慢但对省界这样的数据值得。from shapely.geometry import MultiPolygon, Polygon from shapely.ops import unary_union import geopandas as gpd gdf gpd.read_file(central_asia/tj_adm1.shp) # 先修复非法几何再抽稀 gdf[geometry] gdf.geometry.buffer(0) # 容差 0.01 度约等于 1 公里级别 simplified gdf.geometry.simplify(tolerance0.01) gdf[geometry] simplified容差参数直接决定抽稀程度我的常用三档如下用途容差效果省级分析底图0.01约 1 千米粒度边界细节保留较多网页展示底图0.02约 2 千米粒度文件体积减半小比例尺专题图0.05约 5 千米粒度形状明显简化只适合宏观展示注意纬度越高经度方向对应的地面距离越短同一容差在不同国家效果不一样五个国家混用时以面积损失和实际目视为准。6.2 面积损失验证与最后输出抽稀最怕把边界细节抽没了造成面积估算失真。我习惯在抽稀后立刻做一次面积损失验证area_before gdf.geometry.area.sum() area_after simplified.area.sum() loss_ratio (area_before - area_after) / area_before print(面积损失比例:, loss_ratio)经验值是省级底图的面积损失比例控制在 1% 以内超过 3% 基本说明容差设置过大需要调小重来。早年我图省事直接用 simplify 通吃所有国家结果塔吉克斯坦山区一个省份的形状被压得丢了一角后来养成习惯抽稀后必须叠加在线底图目视一遍再输出最终结果。确认没问题后把处理好的 gdf 写回 GeoJSON 或 GPKG 作为交付格式shp 仅在需要兼容老系统时才保留一份。这套流程走下来五个国家的底图在坐标系、属性、体积和拓扑层面才算真正能交付。希望帮到你。本文还有配套的精品资源点击获取