简介:这份资源是面向GIS从业者、地理数据分析人员及规划相关专业学生的1:100万比例尺中国2017年县级行政区矢量边界数据集,可用于人口统计、城市规划、环境保护、灾害管理与交通规划等空间分析场景,帮助读者快速获得统一、规范的县级行政单元底图。压缩包共7个文件,约46.33MB,以shp主文件承载几何图形,dbf存储县名与代码等属性,prj定义CGS_WGS_1984坐标系,shx、sbn、sbx提供空间索引以加速检索,xml记录元数据,配套结构完整、开箱即用。目前已有615人学习下载。读者可直接将其与人口密度、地形地貌、气候等数据叠加分析,揭示地理模式与趋势,也可作为制图底图或空间统计的基础数据,省去自行收集与配准边界的时间,适合需要可靠县级行政边界的中高级GIS用户。
1. 拿到一份 2017 县级行政区 shp,先想清楚它能干什么
县级行政区划矢量数据在 GIS 圈子里属于那种“平时不觉得稀罕,真要用时到处找不到干净版本”的东西。一份 2017 年的县级行政区 shp 文件,本质上是把当年全国县级单元的边界、名称、行政代码以面要素的形式固化下来,配合基础地理数据库里的道路、水系、居民地等图层,能撑起人口统计制图、专题图底图、空间叠加分析、区域规划前期底图这一整条链路。它解决的核心问题是“空间单元对齐”:你手上有一堆按县统计的表格数据,缺一张能把数字落到地图上的边界底图。适合谁?做国土空间、民政区划、统计年鉴可视化、教学演示、以及需要历史年份快照做对比分析的从业者。2017 这个年份很关键,它是一份时间切片,不是“最新最全”,用之前必须先接受这个前提。
2. 2017 县级行政区 shp 的字段结构与坐标系:先读懂再动手
拿到 shp 不要急着往 QGIS 或 ArcGIS 里拖,先搞清楚它到底带了什么。一个 shapefile 从来不是单个文件,而是.shp(几何)、.shp.xml(元数据)、.dbf(属性表)、.prj(投影)、.shx(索引)这一组,少一个都可能翻车。基础地理数据库出品的县级行政区图层,属性字段通常围绕行政区划代码、名称、上级代码、几何面积这几类组织,但不同来源命名差异很大,必须自己核对。
2.1 用 ogrinfo 把图层“体检”一遍
我一般第一步不是开桌面软件,而是命令行体检,快且不污染工程。
# 查看 shp 的图层名、要素数、坐标系、字段定义 ogrinfo -so -al county_2017.shp # 只看字段列表,快速确认有没有行政代码和名称 ogrinfo -so county_2017.shp county_2017 | grep -E "Field|Geometry"-so是 summary only,不读几何只读元信息,几秒钟出结果;-al表示所有图层。输出里重点看三样:Feature Count(要素数,全国县级单元大致在两千八百上下,明显偏离就要怀疑是不是只给了某个省)、Geometry(应为 Polygon 或 MultiPolygon)、Extent(范围是否覆盖你关心的区域)。字段部分要确认有没有类似adcode、name、parent的列,没有行政代码的版本做关联统计会非常痛苦。
2.2 坐标系与投影:别让面积算错一个数量级
基础地理数据库常见的是地理坐标系(经纬度,单位度),而做面积统计、缓冲区、叠加时必须用投影坐标系(单位米)。这是新手最容易忽略、老手也常偷懒的一步。
import geopandas as gpd gdf = gpd.read_file("county_2017.shp") print(gdf.crs) # 看原始坐标系,常见为 EPSG:4326 print(gdf.geom_type.value_counts()) print(gdf.columns.tolist()) # 面积统计前必须投影到等积或等距坐标系,这里用常见的 Albers 等积投影示例 gdf_proj = gdf.to_crs("+proj=aea +lat_1=25 +lat_2=47 +lat_0=0 +lon_0=105 +datum=WGS84 +units=m") gdf_proj["area_km2"] = gdf_proj.geometry.area / 1e6 print(gdf_proj[["name", "area_km2"]].head())to_crs里的 Albers 参数lat_1、lat_2是标准纬线,lon_0是中央经线,这套参数在国内全域制图中很常见,但如果你只做某个省,标准纬线应换成该省范围,否则边缘变形会偏大。area / 1e6是把平方米换成平方公里。注意:直接对 EPSG:4326 的几何调.area得到的是“平方度”,毫无物理意义,这个坑每年都有人踩。
2.3 属性表清洗:名称、代码、空几何三件事
县级数据里常见的脏点:名称带空格或全角括号、行政代码被存成数值型丢了前导零、个别要素几何为空或自相交。
# 名称去空格、代码补零、剔除空几何 gdf["name"] = gdf["name"].astype(str).str.strip() gdf["adcode"] = gdf["adcode"].astype(str).str.zfill(6) # 县级代码统一 6 位 gdf = gdf[gdf.geometry.notna() & ~gdf.geometry.is_empty] gdf = gdf[gdf.geometry.is_valid] # 先过滤明显无效几何 print(len(gdf))zfill(6)是关键,行政区划代码是字符串语义,一旦被读成整数,110101变成110101还好,但带前导零的省级拼接就会错位。is_valid过滤掉自相交多边形,避免后续空间连接报拓扑错误。清洗完再落盘,别在原文件上反复覆盖。
3. 把县级 shp 接进分析流程:空间连接、裁剪与制图底图
数据读懂了,接下来是它真正产生价值的地方——和你的业务表对齐。这一章按“关联 → 裁剪 → 出图”的顺序走,每一步都给可复现的代码和参数解释。
3.1 用行政代码做属性关联,而不是靠名称
名称关联是血泪教训:同名县、简称、民族自治县全称差异,匹配率能掉到七八成。行政代码是唯一稳定键。
import pandas as pd stats = pd.read_csv("county_stats_2017.csv", dtype={"adcode": str}) stats["adcode"] = stats["adcode"].str.zfill(6) merged = gdf.merge(stats, on="adcode", how="left") missing = merged[merged["指标值"].isna()] print(f"未匹配要素数: {len(missing)}") print(missing[["adcode", "name"]].head(10))dtype={"adcode": str}在读 CSV 时就把代码锁成字符串,避免 pandas 自动推断成整数。how="left"保证边界要素不丢,未匹配的用isna()单独捞出来人工核对——通常是代码版本差异(2017 年后有区划调整)或统计表本身缺项。这一步不要跳过,未匹配清单就是你的数据质量报告。
3.2 按研究区裁剪:clip 与 mask 的取舍
全国数据动辄几百 MB,做市级研究没必要全量加载。裁剪有两种常见做法:按边界clip保留几何交集,或按掩膜mask只留完全落入的要素。
study_area = gpd.read_file("study_boundary.shp").to_crs(gdf.crs) # 方案一:clip,保留与边界相交的部分并裁掉外部 clipped = gpd.clip(gdf, study_area) # 方案二:mask,只保留质心落在研究区内的完整县级单元 masked = gdf[gdf.geometry.representative_point().within(study_area.unary_union)] print(len(clipped), len(masked))clip适合出图,边界干净;mask适合统计,保证每个县是完整单元不被切碎。representative_point()比centroid稳,凹多边形质心可能落在外面。unary_union把研究区合并成单一几何再判断包含,比逐要素循环快一个量级。两种结果数量不同是正常的,选哪个取决于你要“图好看”还是“数对得上”。
3.3 出专题图底图:分类与配色别踩统计陷阱
县级单元做分级设色,最容易被忽略的是分类方法。等间距(equal interval)在县级数据上几乎必然翻车,因为少数大城市指标极高,其余全挤在低值段。
import matplotlib.pyplot as plt fig, ax = plt.subplots(figsize=(10, 8)) merged.plot(column="指标值", cmap="YlOrRd", scheme="quantiles", k=5, legend=True, edgecolor="white", linewidth=0.3, ax=ax, missing_kwds={"color": "lightgrey", "label": "无数据"}) ax.set_axis_off() plt.savefig("county_choropleth.png", dpi=200, bbox_inches="tight")scheme="quantiles"分位数分级,每级要素数接近,视觉区分度好;k=5是级数,超过 7 级人眼难分辨。missing_kwds把未匹配单元标灰,避免“白块被误读成零值”。edgecolor="white"加细边线让相邻县可辨。dpi 200 够印刷级预览,正式出版再上 300。
4. 2017 县级行政区 shp 的避坑清单:五个真实翻车现场
这一章全是踩过的坑,按“现象 → 原因 → 解决”写,能省你至少两天返工。
4.1 要素数对不上:不是数据坏了,是口径变了
现象:全国要素数只有两千六百多,比预期少一两百。原因:2017 年之后有撤县设区、合并,不同来源的“2017 版”可能混入了调整后的边界,或本身只覆盖陆地不含某些管理单元。解决:先确认数据说明里的统计口径,用行政代码去重后计数,再和当年区划简册的县级数量对照;差异集中在某几个省就逐省核对,别急着全量重投影。
4.2 中文属性乱码:dbf 编码是黑匣子
现象:.dbf里名称显示成问号或乱码。原因:shapefile 的 dbf 对中文编码支持不统一,常见 GBK 与 UTF-8 混用,GDAL 默认按 Latin-1 读。解决:读的时候显式指定编码,gpd.read_file("county_2017.shp", encoding="gbk"),不行再试utf-8;确认后统一转存为 GeoPackage 或 GeoJSON,绕开 dbf 编码问题。
4.3 空间连接结果翻倍:几何重叠与重复要素
现象:merge 或 sjoin 后行数暴涨。原因:边界数据存在重复要素,或相邻县共享边界导致intersects命中多次。解决:先drop_duplicates(subset="adcode")去重;空间连接用predicate="within"或先取代表点再连接,避免面与面相交的多对多。
4.4 面积算出来离谱:投影没换或单位没除
现象:某县面积显示几十万。原因:对经纬度几何直接算面积,单位是平方度。解决:先to_crs到米制投影再.area,并统一除以1e6转平方公里;跨纬度大的区域用 Albers 等积投影,别用 Web Mercator 算面积。
4.5 出图边界锯齿与缝隙:简化与拓扑
现象:放大后县界有细缝或锯齿。原因:原始数据精度高但相邻要素节点不共享,或做过简化未保持拓扑。解决:出图前用simplify(tolerance=0.001, preserve_topology=True)适度简化,tolerance 按投影单位调;缝隙明显时用buffer(0)修复自相交,但会轻微改变边界,统计用途慎用。
5. 让 2017 快照可复用:版本化存储与跨年对比的实操技巧
一份 2017 年的县级 shp,最大的价值不在“当年出图”,而在“作为时间切片参与对比”。我一般会把它转成 GeoPackage 做版本化存储,字段里加一列vintage标记年份,后续 2019、2021 的版本同表管理,对比时按代码对齐、按年份分组。
# 转存 GeoPackage,加年份标记,便于多版本共存 gdf["vintage"] = 2017 gdf.to_file("county_admin.gpkg", layer="county_2017", driver="GPKG") # 跨年对比:按 adcode 对齐,找出边界或归属变化的单元 old = gpd.read_file("county_admin.gpkg", layer="county_2017") new = gpd.read_file("county_admin.gpkg", layer="county_2021") changed = set(old["adcode"]) ^ set(new["adcode"]) # 对称差集即新增/撤销 print(f"区划变动单元数: {len(changed)}")driver="GPKG"单文件存多图层,比一堆 shp 好管理,也规避了 dbf 编码和字段名长度限制。^对称差集一次捞出“只在旧版”和“只在新版”的代码,再拿这些代码回查名称,就是一份区划调整清单。注意 GeoPackage 的字段名不要用中文,跨工具兼容性差,用拼音或英文列名、中文放值。
一个具体技巧:做跨年对比图时,别用两套配色硬拼,而是用“变化类型”单图层表达——新增、撤销、边界调整各一色,未变单元浅灰打底。这样一张图讲清十年区划演变,比两张并排图信息密度高得多。我自己的习惯是每次拿到新年份数据,先跑一遍对称差集,把变动清单存成 CSV 归档,三年后回看就是一份现成的区划沿革台账。数据这东西,当时觉得麻烦的版本标记,日后都是后悔药。希望帮到你。
本文还有配套的精品资源,点击获取