☰
全国省市县三级行政区划shp数据处理全攻略:从坐标系到代码清洗
2026/10/12 1:43:35 网站建设 项目流程

简介:全国省级、地市级、县市级行政区划shp.zip 是一套面向GIS应用的中文行政区划基础数据,适用于地图制图、空间分析、区域规划与业务覆盖研究等场景,适合GIS开发人员、数据分析师及城市规划相关从业者使用。压缩包共182个文件,以Shapefile核心组件中的shp几何文件、dbf属性表、shx索引和prj坐标参考文件为主,另有adf、dat、xml等栅格与辅助文件,完整覆盖全国省、市、县三级行政区域边界及名称、行政代码等属性。整体体积约47.71MB,便于下载与本地调用;目前已有4058人学习这份数据。借助ArcGIS、QGIS或Python的GDAL/OGR等工具,用户可直接读取、裁剪、合并或叠加分析这些边界数据,快速搭建行政区划底图,用于人口经济数据关联、防灾分区、选址评估等实际项目,节省自行拼接与清洗基础地理数据的时间。

1. 一份全国三级行政区划shp包,解决的不只是画地图

"全国省级、地市级、县市级行政区划shp.zip"这串文件名,对常和地图打交道的开发者和分析师来说,意味着三样东西同时到位:一份拿来就能用的边界底图、一套可做纵向匹配的行政区划代码、以及一个大概率需要你亲手处理坐标系和编码问题的数据包。它解决的不只是"我能画一张覆盖全国的地图",而是"我能把业务数据按照省、市、县三个尺度准确挂上去"。适合GIS工程师、数据可视化从业者,以及任何需要在业务系统里做空间归属判断的人。

如果你期待解压后双击就能出图,那可能会失望。这份数据的价值在后续处理——投影统一、编码修复、层级校验。后面每一步都会直接影响业务结果,而踩坑的地方也恰恰在这几个环节。接下来按我自己的处理顺序讲:先读懂,再转换,后裁剪,最后校验。

2. 读懂数据本身:坐标系、图层结构与行政区划代码规则

处理任何shp之前,先花五分钟把zip里的东西摸清楚,比多写两行转换命令划算得多。Shapefile虽然叫"一个文件",但实际是一组同主名文件的集合,解压后你会看到一串同名但扩展名不同的文件。缺了某个附属文件,轻则打不开,重则坐标系错乱、属性全丢。

扩展名作用缺失后果
.shp几何坐标本体无法恢复
.shx几何索引部分软件无法读取
.dbf属性表只剩图形没有名称
.prj投影描述坐标系未知
.cpg编码声明中文乱码概率大幅上升

解压后的第一件事,就是清点这些附属文件是否齐全。我见过不止一次zip包里的.prj丢失,导致后续所有叠加分析错位。如果缺文件,先向数据来源方确认有没有补全版本,别急着修复,手动补投影信息是能救,但容易把错误坐标系当成正确坐标系带进业务流程。

2.1 三级图层是三个独立文件:层级关系与属性字段

省级、地市级、县市级是三个独立shp,不是一份数据里带三个字段。它们各自有几何、各自有属性表,图层之间的"父子关系"不靠几何包含判断,而是靠行政区划代码的数值前缀。属性表里常见的字段组合是:名称、行政代码、级别、面积。有的数据包还会带周长字段,但第三方数据包的字段名经常不一致,有的叫"省",有的叫"NAME",代码字段也有ADCODE、PAC、GB_CODE等变体,拿到手先看字段清单再写业务代码。

处理的第一步是用QGIS或Python打开属性表,确认名称和代码两列是否对应。如果表里只有名称没有代码,后续按层级的自动匹配会非常痛苦,只能靠空间位置反推归属,那就要写空间包含判断了。还有一类情况是名称有拼音和中文混杂,这种需要先做一份清理映射,而不是直接拿原始值去join业务表。

2.2 坐标系一眼认出来:WGS84、CGCS2000与Web墨卡托

shp数据包里最常见的坐标系有三种,判断方法、适用场景都不相同,搞错了后面全盘皆输。

坐标系EPSG编码常见表现适用场景
WGS84经纬度4326范围约经度-180到180,纬度-90到90通用GIS分析、GeoJSON交换
CGCS2000经纬度4490数值范围和4326接近,但坐标有厘米级差异国内国土、规划项目交付
Web墨卡托3857X/Y是米制,全国范围数值到千万级互联网地图加载、前端叠加

判断方法是先打开.prj文件看坐标系名称,或者用GDAL的ogrinfo直接读。真正容易翻车的是.prj缺失的情况,工具会报"未知坐标系"。此时看坐标数值范围能猜个八九不离十:经纬度坐标绝对值不会超过180和90,投影坐标动不动就是几百万上千万。有个反直觉的点:CGCS2000和WGS84的经纬度坐标系在数值上很接近,同一位置坐标差通常在半米到几十米之间,小比例尺出图完全看不出区别,但做精确测量时要统一到同一套基准,否则后面对齐边界时会发现几米的系统性偏移。

选择哪种坐标系取决于下游。前端叠加互联网地图用3857;做空间查询、面积计算建议转回4326或4490的经纬度坐标系;如果业务方要求CGCS2000高斯投影带,记得确认是3度带还是6度带以及中央经线编号,投影带选错会得到完全错位的结果。

2.3 行政区划代码:六位数字里藏着三层级联关系

行政区划代码的标准规则是六位数字:前两位省级、中间两位地市级、后两位区县级。拿到一个代码就能立刻判断它属于哪一层、上级是谁。用Python或SQL表达,就是省级代码=前两位加四个零,地市级代码=前四位加两个零,县级就是完整六位。这个规则是整个数据包的灵魂,后面第6章的血缘校验也完全依赖它。

但光知道规则不够,第三方shp包的代码至少有两个常见变体。一是六位变十二位:属性表里存的是含乡级的12位代码,对齐前必须先截取前六位。二是省直辖县级市问题:部分县级市不归属任何地级市,代码中间两位不是市级代码,而是省级特殊段位。这种要素按常规规则去匹配地市层会找不到父级,属于正常现象而不是数据错误,处理时要单独归类。

另外,代码是字符串还是数值也会影响匹配。dbf里代码字段如果被读取成数字类型,前导零会被丢掉,比如代码"110000"变成110000再转回字符串时恢复不了前导零。处理第一步先把代码列统一转成字符串并用zfill补足位数,能省掉后面一堆莫名其妙的匹配失败。

3. 从zip到可用图层:检视、坐标转换与编码修复的完整命令

这一章开始上手操作。我的习惯顺序是"先检视、再转换、最后复核输出",一套流程下来,十分钟内就能把一份状态不明的shp变成干净的可用数据。

3.1 解压后的第一道检查:用GDAL确认识别与完整性

GDAL/OGR是行业标准的矢量处理工具集,所有GIS从业者电脑里基本都有。进入解压目录后,先对每个图层跑一遍概要检查:

# -so 只输出概要,避免刷屏 ogrinfo -so 省级.shp 省级

-so是summary only,不加这个参数会把每条要素的属性都打出来,省级图层还好,县市级几千条要素会直接刷屏。命令输出的几个关键项要盯紧:图层名、要素数量、几何类型、范围extent、投影描述。要素数量和预期不符时,优先怀疑zip解压不完整或dbf字段损坏。全国省级、地市级、县市级三层数据的常见量级分别是几十个、三四百个、两千到三千个左右,如果数量级对不上,就要回去查数据来源。

想快速查看属性内容,用-limit限制返回条数:

# 只打印前3条要素的完整属性 ogrinfo -limit 3 省级.shp 省级

这个命令能顺便发现中文是否乱码、字段名长什么样,为后面的编码修复提供依据。整个过程不需要打开桌面GIS软件,命令行效率高很多。

3.2 统一坐标系:把三个图层都转成WGS84或Web墨卡托

检查完投影后做统一转换。以转到WGS84经纬度为例:

# 转换地市级图层,覆盖输出 ogr2ogr -t_srs EPSG:4326 -overwrite 地市级_wgs84.shp 地市级.shp # 转换县市级图层 ogr2ogr -t_srs EPSG:4326 -overwrite 县市级_wgs84.shp 县市级.shp

-t_srs指定目标坐标系,-overwrite允许重复执行时覆盖已有文件。若没有指定源坐标系,ogr2ogr会尝试从.prj读取;读不到就报错。此时如果明确知道源坐标系,可以用-s_srs EPSG:xxxx手动指定,但前提是你对数据来源有把握,猜错坐标系会让数据偏移几百公里。

不要一次性把三个图层循环转换完就收工。转完第一个图层后,用QGIS加载它,再加载一个你信得过的在线底图叠加检查位置是否对齐,确认无误后再批量转其余图层。坐标转换本身失败的情况少见,但转错坐标系的排查成本极高,多花两分钟做视觉验证,能省下后面几小时。

3.3 中文乱码的真相:GBK与UTF-8在shp属性表里的争夺

shp属性表dbf有个历史包袱:编码不写入强制的元数据字段,生产方可能用UTF-8,可能用GBK,也可能是本机ANSI。同一份zip在不同电脑上打开,中文显示结果可能完全不同。判别当前编码,我一般直接在读取阶段做统一转换,一次性输出成UTF-8:

# 强制把属性编码转为UTF-8,同时统一坐标系 ogr2ogr -lco ENCODING=UTF-8 -t_srs EPSG:4326 \ 县市级_utf8_wgs84.shp 县市级.shp

-lco ENCODING=UTF-8是图层创建选项,决定输出文件的属性编码。如果源文件是GBK但没加这个参数,GDAL默认按UTF-8读,写出后内容就是乱码。反过来也一样,源文件是UTF-8而系统默认GBK,照样乱。所以这个参数不是可选项,是必选项。

更稳妥的做法是先探明源编码再转换。用Python读dbf文件头部的LDID字节,或者直接用file命令:

# 看一眼文件声明的编码 file 县市级.dbf

输出里通常能看到 charset= 字样。不过dbf的编码声明字段经常形同虚设,最终以实际显示效果为准。转完后用ogrinfo -limit 3复核一次,中文名称正常再继续。

4. 筛省、裁边界、减顶点:把全国数据变成自己业务需要的范围

全国图层要素多、顶点多、文件大,生产环境里不可能每次都全量加载。大多数业务只需要部分地区,其余部分要么裁剪掉,要么大幅简化。工具选型上,ogr2ogr命令适合批量处理,GeoPandas适合做需要自定义逻辑的精细操作,两者结合是常见组合。

4.1 保留边界细节还是控制渲染压力:简化容差怎么定

地图简化算法众多,核心思路都是牺牲一定精度换顶点数下降。GDAL默认使用的道格拉斯-普克算法有一个控制参数:容差。容差越大,保留的顶点越少,边界越粗糙。

# 对县市级图层做简化,容差0.005度 ogr2ogr -simplify 0.005 县市级_simplify.shp 县市级.shp

-simplify的参数单位跟随图层坐标系。图层是经纬度时,0.005度大约相当于500米;如果图层是3857米制坐标,0.005就是0.005米,等于没简化。这是最常见的参数理解错误,单位必须提前确认。

用GeoPandas做同样操作时,可以额外保留拓扑正确性:

import geopandas as gpd gdf = gpd.read_file("县市级.shp", encoding="utf-8") # tolerance值为0.005,单位跟随图层坐标系 gdf_simple = gdf.simplify(tolerance=0.005, preserve_topology=True) gdf_simple.to_file("县市级_simplify.shp", encoding="utf-8")

preserve_topology=True让相邻多边形的公共边界在简化后不产生断裂或重叠,这是地图简化最值得记住的参数。它能避免相邻面之间出现细小的白色缝隙,那种缝隙在出图时非常显眼。简化容差的经验值大致是:全国视图用0.01到0.05,省级视图用0.005到0.01,县级精细分析用0.001到0.002,按这个区间起步通常不需要反复调整。

4.2 只留某个业务区域:属性筛选的正确姿势

业务上往往只关心某几个省或某个地市。此时不要用空间裁剪去切割要素,直接按属性筛选最可靠:

# 按省名精确筛选出一个省份 ogr2ogr -where "NAME='某省'" 某省.shp 全国省级.shp

-where后面跟标准SQL条件。字段名的大小写要和dbf实际一致,否则条件匹配不到任何要素,输出一个空文件但命令不报错。条件里的字符串值也要先确认是中文全称、拼音还是简称,三种情况我都遇到过。

最省事的做法是用ogrinfo把字段值去重列出来,再定筛选条件:

# 查看省名字段的全部唯一值 ogrinfo -sql "SELECT DISTINCT NAME FROM 省级" 省级.shp

这样能直接看到字段里存的到底是什么,避免凭猜测写条件。多条件筛选时用AND连接,比如同时限定多个省:"NAME='某省' OR NAME='某市'",注意SQL里字符串用单引号,在bash命令行里外层双引号包裹即可。

4.3 给前端地图用:GeoJSON与TopoJSON的取舍

数据最终要放Web端展示时,GeoJSON是最通用格式,但字段冗余和文件大小也是老问题。用ogr2ogr转GeoJSON时控制两个参数:

# 控制坐标小数位,只保留指定字段 ogr2ogr -f GeoJSON -lco COORDINATE_PRECISION=7 \ -select NAME,CODE 某省.geojson 某省.shp

COORDINATE_PRECISION控制坐标输出的十进制小数位数,对经纬度来说6位约0.1米精度,7位约1厘米,足够绝大多数展示场景。-select只保留需要的字段,面积、周长这类不用的字段全部丢弃,GeoJSON体积能小一半以上。

如果转出来的GeoJSON字段没了中文名,说明源dbf编码问题还没解决,回头做第3.3节的编码统一。TopoJSON体积比GeoJSON更小,因为它把相邻多边形的公共边界只存储一次,但如果你的业务要做空间查询、属性点击,TopoJSON解析后重建拓扑反而增加复杂度,通常只在纯展示场景使用。

5. 行政区划shp的避坑指南:飞地、代码失效与层级对不齐

这一章写的是我处理多份行政区划数据时真实踩过的坑,每条按现象、原因、解决三个层次说清楚。

5.1 相邻多边形出现缝隙或重叠:共享边不一致

现象:单独看省级图层一切正常,把地市级图层叠加到省级上,发现某些边界处出现细小白缝或重叠区域,放大看两段边界几乎重合但不完全一致。原因:三级图层可能来自不同的生产批次,相邻面要素的共享边在各自图层里不是同一串坐标,简化算法处理时保留的顶点也不一致,几何上天然对不齐。解决:不要试图用空间操作去"吸附",那会让边界变得更乱。常见做法是选取一个层级作为基准层,其他层级出图时只做参考;涉及多层级叠加分析的场景,用行政区划代码前缀判断归属,不要用空间包含判断。多级图层的公共边完全重合本来就是一种奢求,承认这一点能省掉很多无效操作。

5.2 撤县设区之后的"幽灵县":行政区划代码失效

现象:县市级图层里存在一个县,但在最新的行政区划公告中已经找不到它,其边界甚至被周围要素覆盖。原因:shp是某个时间点的快照,而行政区划调整持续发生,撤县设区、合并设市年年都有。快照数据不可能自动反映这些调整。解决:用官方发布的最新行政区划代码表与数据比对,把已失效要素标记出来,增加一个"数据时效性"字段区分当前有效与历史有效。特别注意,不要因为边界被覆盖就直接删除该要素,历史快照在回溯分析和周期对比中仍有价值。每次使用前确认数据的时间版本,把它写进数据字典,比用完就忘好得多。

5.3 飞地与嵌入边界:归属关系看起来不正常

现象:某县级区域的地理位置在A市范围内,但行政区划代码前缀和属性都写的是B市。原因:飞地是客观存在的行政现象,不只是数据处理错误。另一部分原因是数据生产阶段把空间归属和代码归属概念混淆了。解决:先到最新行政区划代码表确认该代码的归属。如果代码无误,就接受空间归属与代码归属不一致的现实,在业务统计口径中明确按代码归属还是按空间归属,并在文档里写清楚。千万不要为了"美观"在shp里手动移动边界,那样会污染数据的客观性。

5.4 面积算出来明显不对:经纬度与投影坐标下的单位陷阱

现象:在WGS84图层上直接计算面积,得到的结果要么小得离谱要么大得离谱,和真实面积差好几个数量级。原因:经纬度坐标系算出来的面积单位是"平方度",不是平方米;如果图层是某投影带的局部坐标,离中央经线越远变形越严重。解决:计算面积前把图层投影到适合区域范围的等积投影,比如Albers等积投影或UTM对应分带。另一种常见做法是用PostGIS的ST_Transform转到Web墨卡托再算,但墨卡托本身不是等积投影,高纬度误差明显,不算理想方案。我的一般做法是:只算占比比较时可以用经纬度近似值,要出精确结果必须换等积投影,这条没有捷径。

5.5 名称与代码错位:属性表里对不上号

现象:属性表中某要素的名称写的是A县,但代码对应的却是B县,单独看任何一列都不容易发现问题。原因:dbf属性编辑时行序错位或者手工录入错误,这类问题在免费下载的数据包里出现概率不低。解决:用第6章的血缘校验脚本逐要素核对代码前缀,也可以把名称列和代码列做一次交叉验证,通常能找到几十条异常。这个坑隐蔽性强,线上地图一旦用错名称,用户反馈问题后排查成本极高,所以属性层面的校验务必在入库前完成。

6. 进阶:用GeoPandas验证省-市-县血缘关系,产出干净可维护的底图

数据要长期使用,就得让三个层级的代码关系对得上。我每次拿到新数据都会跑一段血缘校验脚本:把县级的代码前缀和地市级、省级代码一一对应验证,找出没有父级代码的要素,单独导出问题清单。

import geopandas as gpd # 假设三份文件都已转好编码与坐标系 prov = gpd.read_file("省级_wgs84.shp") city = gpd.read_file("地市级_wgs84.shp") county = gpd.read_file("县市级_wgs84.shp") # 统一代码列格式:转字符串,截前6位(兼容6位和12位代码) prov["code6"] = prov["CODE"].astype(str).str[:6] city["code6"] = city["CODE"].astype(str).str[:6] county["code6"] = county["CODE"].astype(str).str[:6] # 校验县到地市:县代码前4位能在市级图层找到 city_codes = set(city["code6"].str[:4]) county["parent_city_ok"] = county["code6"].str[:4].isin(city_codes) # 校验地市到省:市代码前2位能在省级图层找到 prov_codes = set(prov["code6"].str[:2]) city["parent_prov_ok"] = city["code6"].str[:2].isin(prov_codes) # 导出问题记录 issue_city = city[~city["parent_prov_ok"]] issue_county = county[~county["parent_city_ok"]] issue_city.to_file("市级代码无父级.shp", encoding="utf-8") issue_county.to_file("县级代码无父级.shp", encoding="utf-8") print("市级异常:", len(issue_city), " 县级异常:", len(issue_county))

这段脚本只依赖两个操作:把代码列转成字符串并按位截取,再用isin做集合归属判断。脚本不判空间位置,只判编码血缘,这正是行政区划数据校验中最该先用的一招。输出两个异常shp后,在地图里看一眼异常要素的大致分布,基本就能判断是数据过期、代码规则特殊,还是属性录入错误,然后分别处理。

跑通这套流程之后,我会把省、市、县三份数据和校验结果一起归档,文件名里写明坐标系、编码和时间戳,比如"省级_wgs84_utf8_2025.shp"。这样后续任何人拿去用都不会再问"这是哪年的数据、什么投影"之类的问题。数据不难找,难在把它变成能放心用、可长期维护的底图。这套血缘校验加归档的习惯,帮我少走了很多弯路。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询