简介:这份资源是面向GIS从业者、地理信息专业学生及城市规划研究人员的基础地理数据库,提供2017年中国各县级行政区的矢量边界数据,采用1:100万比例尺,适合大范围空间分析与专题制图。压缩包共7个文件,约46.33MB,以SHP格式为核心,配套DBF属性表存储县名与代码,PRJ定义CGS_WGS_1984坐标系,SBN、SBX、SHX等索引文件提升检索效率,XML则记录元数据信息。已有614人学习下载,说明其在教学与项目实践中具有一定参考价值。读者可借助该数据完成人口统计、城市规划、环境保护、灾害管理及交通规划等场景的叠加分析,结合其他数据源揭示地理模式与趋势,为决策提供依据。数据坐标系明确、文件结构完整,便于在主流GIS软件中直接加载与二次处理。
1. 1100万基础地理数据库里的县级行政区:这份2017年shp文件到底能干什么
如果你手头正好有一份 1100 万基础地理数据库的 2017 年县级行政区 shp 文件,先别急着双击打开。很多人第一次拿到它,以为就是个普通的边界线图层,拖进软件里一看,属性表里字段名全是拼音缩写,坐标系也不是常见的经纬度,当场就懵了。这份数据的价值恰恰藏在它的“不友好”里——它是全国尺度的县级行政区划矢量边界,1100 万比例尺意味着几何精度经过综合取舍,适合做全国范围的专题制图、空间统计和区域分析,而不是拿来做地块级别的测绘。
它适合谁?做国土空间规划前期底图的人、跑全国县域经济指标空间化的人、需要把统计数据挂到行政区上做热力图的人,以及做地理信息教学演示的人。不适合谁?需要村级边界、需要最新行政区划调整结果、需要高精度地形叠加的人。2017 年这个时间节点很关键,它卡在第三次全国土地调查之前,很多县的边界还是调整前的状态,用的时候得心里有数。这一章先把这份数据是什么、能解决什么讲清楚,后面再一步步拆怎么用、怎么避坑。
2. 拿到shp先别急着画图:坐标系、字段和几何类型的三重确认
2.1 为什么1100万比例尺的县级边界不能直接量面积
1100 万基础地理数据库的县级行政区 shp,最常见的坐标系是西安80 或 CGCS2000 的地理坐标系,单位是度。直接在这种数据上算面积,得到的是平方度,没有任何实际意义。更麻烦的是,1100 万比例尺的几何经过了制图综合,边界线被简化过,小岛屿可能被合并,飞地可能被处理掉。如果你拿它去和 1:1 万的土地利用数据叠加,会发现边界对不上,这不是数据错了,是比例尺决定的精度差异。
常见做法是先把地理坐标系投影到合适的投影坐标系,再算面积。全国范围一般用 Albers 等积投影,参数里中央经线取 105°E,两条标准纬线取 25°N 和 47°N。这样算出来的面积和实际面积偏差最小。我一般会在 QGIS 或 ArcGIS 里先做投影转换,再在属性表里新建面积字段,用计算几何功能算。注意,投影转换会改变几何坐标,但不会改变属性表里的行政区代码和名称,所以转换前最好备份一份原始数据。
# 用 geopandas 做 Albers 投影并计算面积 import geopandas as gpd # 读取 shp,注意编码,中文路径和字段容易出问题 gdf = gpd.read_file(r"county_2017.shp", encoding="utf-8") # 查看原始坐标系 print(gdf.crs) # 定义 Albers 等积投影,适合全国范围 albers_crs = "+proj=aea +lat_1=25 +lat_2=47 +lat_0=0 +lon_0=105 +x_0=0 +y_0=0 +ellps=GRS80 +units=m +no_defs" # 投影转换 gdf_albers = gdf.to_crs(albers_crs) # 计算面积,单位平方米,再转平方公里 gdf_albers["area_km2"] = gdf_albers.geometry.area / 1e6 # 输出前几行看看 print(gdf_albers[["name", "area_km2"]].head())这段代码的关键在to_crs那一步,它把地理坐标转成投影坐标。lat_1和lat_2是标准纬线,选 25 和 47 是因为中国纬度范围大约在 18°N 到 53°N 之间,这两条线能保证全国面积变形较小。lon_0取 105 是因为中国经度范围大约 73°E 到 135°E,中央经线取中间值。ellps=GRS80是 CGCS2000 的椭球参数,如果原始数据是西安80,椭球参数要换成IAU76或对应的,否则会有系统性偏差。算完面积后,你会发现有些县的面积明显偏小,那可能是飞地或者岛屿被综合掉了,用的时候要结合实际情况判断。
2.2 属性表里的字段名像密码,怎么快速读懂
1100 万基础地理数据库的县级行政区 shp,属性表字段通常包括PAC、NAME、CODE这类缩写。PAC是行政区代码,NAME是名称,CODE可能是更细的分类码。不同批次的数据字段名可能不一样,有的用XZQDM表示行政区代码,有的用ADCODE。拿到数据后第一件事是打开属性表,看字段名和字段值,别急着按字段名猜。
我一般会先导出属性表到 CSV,用 pandas 看一眼字段类型和唯一值。如果字段名是拼音缩写,可以对照《中华人民共和国行政区划代码》标准来理解。县级行政区代码是 6 位,前两位是省,中间两位是市,后两位是县。2017 年的数据里,有些县可能已经撤县设区了,但代码还是老的,用的时候要核对当年的行政区划简册。
import pandas as pd # 读取属性表,假设已经导出为 csv df = pd.read_csv("county_attr.csv", encoding="gbk") # 查看字段名和类型 print(df.dtypes) # 查看行政区代码的长度分布 print(df["PAC"].astype(str).str.len().value_counts()) # 查看名称字段是否有空值 print(df["NAME"].isnull().sum()) # 按省统计县级单元数量 df["province"] = df["PAC"].astype(str).str[:2] print(df.groupby("province").size().sort_values(ascending=False).head(10))这段代码先看字段类型,如果PAC被读成整数,前导零会丢失,所以要用astype(str)转回来。str.len()看代码长度,正常应该是 6 位,如果出现 5 位或 4 位,说明有前导零丢失或者数据有问题。按省统计能快速发现异常,比如某个省的县级单元数量明显偏少,可能是数据缺失或者代码错误。名称字段有空值的话,后续做空间连接会丢记录,得先补上。
2.3 几何类型是 Polygon 还是 MultiPolygon,决定了你能不能直接做空间连接
县级行政区 shp 的几何类型通常是 Polygon 或 MultiPolygon。MultiPolygon 意味着一个县有多个不相连的几何部分,比如岛屿、飞地。做空间连接时,如果目标数据是点,MultiPolygon 和 Polygon 都能处理;但如果目标数据是面,MultiPolygon 可能会导致一对多匹配,需要先做聚合或拆分。
我一般会先检查几何类型,如果是 MultiPolygon,看有多少个部分,部分特别多的县可能是沿海岛屿县。做空间连接前,如果不需要保留飞地细节,可以用explode把 MultiPolygon 拆成单个 Polygon,或者用dissolve按行政区代码合并。但要注意,dissolve会丢失内部边界,如果后续要做县级内部分析,就不能合并。
# 检查几何类型和 MultiPolygon 的部分数量 geom_types = gdf.geometry.geom_type.value_counts() print(geom_types) # 对 MultiPolygon 计算部分数量 multi = gdf[gdf.geometry.geom_type == "MultiPolygon"] multi["part_count"] = multi.geometry.apply(lambda g: len(g.geoms)) print(multi[["name", "part_count"]].sort_values("part_count", ascending=False).head()) # 如果需要拆成单个 Polygon exploded = gdf.explode(index_parts=True) print(exploded.geometry.geom_type.value_counts())geom_type看整体几何类型分布,part_count看每个 MultiPolygon 有几个部分。部分数量特别多的县,比如超过 100 个,可能是沿海岛屿县,做空间连接时要注意性能。explode会把 MultiPolygon 拆成多个 Polygon,索引会变成多级索引,后续操作要注意重置索引。如果只是做点与面的空间连接,不拆也能用,geopandas 会自动处理,但拆了之后匹配结果更清晰。
3. 从shp到可用底图:投影、裁剪与空间连接的完整操作链
3.1 用 QGIS 做投影转换和裁剪的图形化流程
不是所有人都习惯写代码,QGIS 的图形化操作也能完成投影转换和裁剪。打开 QGIS,把 shp 拖进去,右键图层选“导出”->“保存要素为”,在对话框里选目标坐标系,比如 Albers 投影,然后保存。裁剪的话,先用“矢量”->“地理处理工具”->“裁剪”,输入图层选县级行政区,叠加图层选你的研究区范围,运行后就能得到研究区内的县级边界。
图形化操作的好处是直观,坏处是参数不好记录,换台机器就得重新点一遍。我一般会先用 QGIS 试一遍,确认参数没问题,再用代码批量处理。QGIS 的裁剪工具默认会保留叠加图层的属性,如果不需要,可以在对话框里取消勾选。注意,裁剪后的数据坐标系会继承输入图层,如果输入图层是地理坐标系,裁剪完还是地理坐标系,算面积前还得再投影。
3.2 用 geopandas 做空间连接:把统计数据挂到县上
空间连接是这份数据最常用的操作之一。你有一份县级统计数据,比如 GDP、人口,想挂到 shp 上做专题图。如果统计数据里有行政区代码,直接用属性连接就行,不用空间连接。但如果没有代码,只有县名,就得用空间连接或者模糊匹配。空间连接的前提是统计数据有坐标,比如点数据,把点落到县界里,就能把县的属性赋给点。
# 假设有一个点数据集,包含 GDP 信息 points = gpd.read_file("gdp_points.shp") # 确保两个数据坐标系一致 points = points.to_crs(gdf.crs) # 空间连接,把县的属性赋给点 joined = gpd.sjoin(points, gdf, how="left", predicate="within") # 查看匹配结果 print(joined[["name", "gdp"]].head()) # 检查有多少点没匹配上 print(joined["name"].isnull().sum())sjoin的predicate参数选within,表示点完全落在县界内。如果点落在边界上,可能匹配不上,可以改用intersects。how="left"保留所有点,没匹配上的县名字段为空。匹配不上的原因通常是坐标系不一致、点落在县界外或者县界有拓扑错误。检查方法是用isnull()看空值数量,如果空值很多,先检查坐标系,再用buffer(0)修复几何。
3.3 裁剪到研究区:用掩膜提取和批量导出
全国范围的县级行政区 shp 数据量不小,如果只研究某个省或某个流域,先裁剪能提高后续处理速度。裁剪有两种方式:用研究区边界做掩膜提取,或者用矩形范围做框选。掩膜提取更精确,但要求研究区边界是闭合多边形。框选简单,但会多出一些不需要的县。
# 读取研究区边界 study_area = gpd.read_file("study_area.shp") # 确保坐标系一致 study_area = study_area.to_crs(gdf.crs) # 用研究区边界裁剪 clipped = gpd.clip(gdf, study_area) # 导出为新的 shp clipped.to_file("county_clipped.shp", encoding="utf-8") # 如果研究区是矩形范围,可以用 cx 索引 # clipped = gdf.cx[100:120, 20:40]clip函数会保留落在研究区内的几何部分,如果县界跨越研究区边界,会被切掉一部分。如果不想切,只想选出与研究区相交的县,可以用sjoin加intersects。导出时注意编码,中文路径和字段名容易乱码,建议用英文路径和字段名,或者在to_file里指定encoding。批量导出的话,可以按省循环,每个省导一个 shp,方便后续分省处理。
4. 避坑指南:县级行政区shp处理中最容易翻车的五个地方
4.1 坐标系不统一导致空间连接全空
现象:两个图层明明有重叠,空间连接后结果全是空值。原因:一个图层是地理坐标系,另一个是投影坐标系,或者两个都是地理坐标系但基准面不同。解决:先用gdf.crs查看坐标系,如果不一致,用to_crs统一。如果基准面不同,比如西安80 和 CGCS2000,直接转换会有偏差,需要先做基准面转换,再投影。
4.2 行政区代码前导零丢失导致属性连接失败
现象:用行政区代码做属性连接,匹配率极低。原因:代码字段被读成整数,前导零丢失,比如010000变成10000。解决:读取时指定dtype={"PAC": str},或者读完后用str.zfill(6)补零。导出 CSV 时也要注意,Excel 打开 CSV 会自动把代码转成科学计数法,最好用文本格式打开。
4.3 几何无效导致裁剪和空间连接报错
现象:裁剪时提示几何无效,或者空间连接结果异常。原因:shp 文件在编辑过程中产生了自相交、重复点等拓扑错误。解决:用gdf.geometry.is_valid检查,对无效几何用buffer(0)修复。buffer(0)能解决大部分自相交问题,但会轻微改变几何形状,修复后要重新检查面积变化。
4.4 2017年行政区划调整导致名称对不上
现象:用县名做匹配,发现有些县找不到,或者匹配到错误的县。原因:2017 年之后有些县撤县设区、改名或者合并,用现在的名称去匹配 2017 年的数据,自然对不上。解决:用行政区代码匹配,代码比名称稳定。如果只有名称,先查当年的行政区划简册,确认名称和代码的对应关系。
4.5 1100万比例尺精度不足导致面积统计偏差
现象:算出来的县面积和官方公布面积差很多。原因:1100 万比例尺的边界经过综合,小岛屿和飞地被简化,导致面积偏小或偏大。解决:如果面积精度要求高,换用更大比例尺的数据,比如 1:25 万或 1:5 万。如果只能用这份数据,在报告里注明比例尺和精度限制,别把面积数字当成精确值用。
5. 进阶技巧:用这份数据做全国县域空间自相关分析
5.1 构建空间权重矩阵的三种方式
空间自相关分析的第一步是构建空间权重矩阵。用县级行政区 shp 可以做邻接矩阵、距离矩阵和 K 近邻矩阵。邻接矩阵基于边界相邻关系,适合做 Moran's I;距离矩阵基于质心距离,适合做空间滞后模型;K 近邻矩阵适合数据分布不均匀的情况。我一般先用邻接矩阵,因为县级行政区的邻接关系比较稳定,不容易受质心位置影响。
import libpysal from libpysal.weights import Queen, Rook, KNN # 邻接矩阵,Queen 考虑共享边和共享点 w_queen = Queen.from_dataframe(gdf_albers) # 邻接矩阵,Rook 只考虑共享边 w_rook = Rook.from_dataframe(gdf_albers) # K 近邻矩阵,K=5 w_knn = KNN.from_dataframe(gdf_albers, k=5) # 行标准化 w_queen.transform = "r" w_rook.transform = "r" w_knn.transform = "r" # 查看邻接数量分布 print(w_queen.cardinalities)Queen和Rook的区别在于是否考虑共享点。县级行政区如果只有共享点没有共享边,比如四个县交于一点,Queen会认为它们相邻,Rook不会。KNN的k值需要根据数据分布调整,一般取 4 到 8。行标准化后,权重矩阵每行和为 1,方便后续计算。cardinalities看每个县的邻居数量,如果出现 0,说明有孤岛,需要手动处理。
5.2 用 Moran's I 看县域经济指标的空间聚集
有了空间权重矩阵,就可以算 Moran's I 了。Moran's I 衡量的是空间自相关程度,值在 -1 到 1 之间,大于 0 表示正相关,小于 0 表示负相关,接近 0 表示随机分布。我一般会先用esda库算全局 Moran's I,再看局部 Moran's I 找热点和冷点。
from esda.moran import Moran, Moran_Local # 假设 gdf_albers 里有一个 gdp_per_capita 字段 y = gdf_albers["gdp_per_capita"].values # 全局 Moran's I moran = Moran(y, w_queen) print(f"Moran's I: {moran.I}, p-value: {moran.p_sim}") # 局部 Moran's I moran_local = Moran_Local(y, w_queen) gdf_albers["moran_local"] = moran_local.Is gdf_albers["moran_p"] = moran_local.p_sim # 按显著性分类 gdf_albers["cluster"] = "不显著" gdf_albers.loc[(moran_local.p_sim < 0.05) & (moran_local.Is > 0), "cluster"] = "高-高" gdf_albers.loc[(moran_local.p_sim < 0.05) & (moran_local.Is < 0), "cluster"] = "低-低"全局 Moran's I 的p_sim是置换检验的 p 值,小于 0.05 表示显著。局部 Moran's I 的Is是局部自相关值,正值为高-高或低-低聚集,负值为高-低或低-高异常。分类后可以导出 shp,在 QGIS 里做专题图。注意,gdp_per_capita如果有空值,要先填充或删除,否则会影响结果。
5.3 把分析结果导出成可交互的地图
分析结果最终要给人看,导出成可交互的地图最直观。我一般用folium或kepler.gl做快速可视化。folium适合做网页地图,kepler.gl适合做三维和动态效果。导出前先把数据转成 GeoJSON,注意坐标系要转回 WGS84,因为网页地图通常用 WGS84。
import folium # 转回 WGS84 gdf_wgs = gdf_albers.to_crs("EPSG:4326") # 创建地图,中心点取全国中心 m = folium.Map(location=[35, 105], zoom_start=4) # 添加 Choropleth 图层 folium.Choropleth( geo_data=gdf_wgs, data=gdf_wgs, columns=["name", "gdp_per_capita"], key_on="feature.properties.name", fill_color="YlOrRd", fill_opacity=0.7, line_opacity=0.2, legend_name="人均GDP" ).add_to(m) # 保存为 HTML m.save("county_gdp_map.html")Choropleth的key_on要对应 GeoJSON 里的属性字段,columns里第一个是键,第二个是值。fill_color选YlOrRd是黄到红的渐变,适合表示数值高低。保存成 HTML 后,可以直接用浏览器打开,鼠标悬停能看到数值。如果数据量大,网页会卡,可以按省拆分,或者用矢量瓦片。
这份 2017 年县级行政区 shp 文件,我用了好几年,最大的教训是别把它当成精确的测绘数据用。它的价值在于全国覆盖和统一的属性结构,适合做宏观分析和制图底图。每次用之前,先确认坐标系、字段和几何类型,再检查行政区划调整,最后在报告里注明比例尺和精度限制。希望帮到你。
本文还有配套的精品资源,点击获取