SHP文件实战:山东省行政区划与路网数据GIS分析全流程
简介这份资源面向GIS从业者、城市规划人员及地理数据分析学习者提供2022年7月山东省的矢量地理数据涵盖省、市、县三级行政区划边界以及道路网与铁路网信息可用于空间查询、叠加分析、缓冲区分析及专题地图制作等场景。压缩包共33个文件约37.59MB以shp、dbf、prj、shx、xml等格式为主其中shp存储几何形状dbf保存道路名称、等级、行政代码等属性prj定义坐标系统shx与xml辅助索引和元数据描述各类型配合构成完整可用的GIS数据集。目前已有2018人学习下载适合需要快速获取山东基础地理底图、开展交通规划、灾害响应评估或商业选址分析的用户可直接在ArcGIS、QGIS等软件中加载使用省去繁琐的数据采集与整理环节。1. 拿到一份 SHP 文件之后山东省行政区划与路网数据能跑出什么很多做 GIS 分析的人都有过这种经历拿到一个压缩包解压出来一堆 .shp、.dbf、.shx、.prj双击打不开拖进 QGIS 能看但不知道坐标系对不对想按市县做统计又发现属性表里字段名全是拼音缩写。这份「山东省行政区划省、市、县道路网公路网」的 SHP 文件本质上就是一套典型的矢量地理数据集合覆盖省级、地级市、区县三级行政边界外加道路网和公路网两层线状要素。它能干的事很具体按行政区做数据聚合、做路网密度计算、做可达性分析、做专题图出图。适合谁做国土空间规划的技术人员、做物流选址的分析师、做城市研究的学生以及需要给业务系统灌底图数据的后端工程师。坐标系大概率是 CGCS2000 或 WGS84但别猜后面会讲怎么验。2. 先验坐标系和字段别让第一个图层就翻车2.1 用 ogrinfo 把元数据一次看穿拿到 SHP 第一件事不是打开 QGIS 画图而是用命令行把元数据读出来。GDAL 自带的 ogrinfo 是最稳的工具没有之一。# 查看 SHP 文件的图层摘要信息包括几何类型、要素数、坐标系 ogrinfo -so -al shandong_province.shp # 查看前 3 个要素的完整属性确认字段名和编码 ogrinfo -al -fid 1 -fid 2 -fid 3 shandong_city.shp-so表示 summary only只输出摘要不输出每个要素-al表示 all layers遍历所有图层。输出里重点看三行Geometry:告诉你这是 Polygon 还是 LineStringFeature Count:告诉你要素数量省级应该是 1地级市 16 左右区县 130 多Layer SRS WKT:里的AUTHORITY[EPSG,4490]就是坐标系代码4490 是 CGCS2000 地理坐标系4326 是 WGS84。如果 ogrinfo 输出里 SRS 显示为(unknown)说明 .prj 文件缺失或损坏。这时候不要硬猜用 QGIS 打开后手动指定坐标系再导出或者找原始数据提供方要 .prj 文件。我一般会先把所有图层的坐标系统一成 EPSG:4490因为国内行政区划数据用 CGCS2000 是主流做法后续做面积计算和距离量测时偏差最小。2.2 字段名乱码和编码问题SHP 的 .dbf 文件对中文支持一直是个老大难。用 ogrinfo 看到字段值显示为????或乱码基本就是编码问题。常见做法是设置SHAPE_ENCODING环境变量# 强制以 GBK 编码读取 dbf适用于国内老数据 SHAPE_ENCODINGGBK ogrinfo -al shandong_county.shp # 如果 GBK 不对试 UTF-8 SHAPE_ENCODINGUTF-8 ogrinfo -al shandong_county.shp参数说明SHAPE_ENCODING是 GDAL 的 shapefile 驱动专用环境变量只影响 .dbf 的文本读取不影响几何。如果两种编码都试过还是乱码那可能是数据生产时用了自定义编码页这时候用 Python 的 dbfread 库逐字节读出来看十六进制再决定怎么转。别在这上面耗太久实在不行就按 FID 顺序重新挂接一份干净的属性表。2.3 道路网和公路网的区别要先搞清楚标题里同时出现了「道路网」和「公路网」这两个不是一回事。道路网通常包含城市道路、乡村道路、匝道等所有可通行路径要素密度高、属性字段多公路网一般只包含国道、省道、县道等纳入公路管理体系的线路要素少但等级属性明确。拿到数据后先看两个图层的要素数量和字段结构图层典型要素数山东关键字段几何类型道路网数十万条道路名称、类型、宽度LineString公路网数万条路线编号、等级、路面材质LineString区县边界130区县代码、名称、面积Polygon如果道路网要素数明显偏少可能是只抽了主干道如果公路网里出现了「城市主干路」这种字段值说明数据生产方把两个概念混在一起了。这直接影响后续分析口径做路网密度时用哪个图层结论可能差一倍。3. 用 Python 把三级行政区划和路网串起来做分析3.1 环境准备与依赖安装# 推荐用 conda 建独立环境避免 GDAL 版本冲突 conda create -n shandong_gis python3.10 conda activate shandong_gis # 安装核心库geopandas 会自动带 GDAL 和 Fiona conda install -c conda-forge geopandas matplotlib contextily pip install shapely pyproj rtreegeopandas是操作矢量数据的核心库底层调 GDAL 做 I/O调 Shapely 做几何运算。contextily用来加底图出图时有用。rtree是空间索引库做空间连接时能快一个数量级。版本上 geopandas 0.14 以上对 pandas 2.x 兼容更好如果遇到AttributeError: GeometryArray object has no attribute crs这类报错八成是版本不匹配回退到 0.12 或升级到最新。3.2 读取三级行政区划并统一坐标系import geopandas as gpd # 读取三个层级的行政区划 province gpd.read_file(shandong_province.shp, encodingGBK) city gpd.read_file(shandong_city.shp, encodingGBK) county gpd.read_file(shandong_county.shp, encodingGBK) # 检查坐标系统一转为 EPSG:4490 for name, gdf in [(province, province), (city, city), (county, county)]: print(f{name}: CRS {gdf.crs}, 要素数 {len(gdf)}) if gdf.crs is None: gdf.set_crs(epsg4490, inplaceTrue) elif gdf.crs.to_epsg() ! 4490: gdf.to_crs(epsg4490, inplaceTrue) # 验证省级图层应该只有 1 个要素 assert len(province) 1, 省级图层要素数异常 # 验证区县图层要素数应大于地级市图层 assert len(county) len(city), 区县数应多于地级市数encodingGBK参数直接传给 Fiona 的打开选项解决中文乱码。set_crs和to_crs的区别要分清前者是「声明」坐标系用于原本没有 CRS 信息的情况后者是「转换」坐标系会实际重算坐标值。如果数据本身有 CRS 但你不确定对不对先用to_crs转成 4490 再看范围是否落在山东经纬度区间东经 114°–122°北纬 34°–38°偏得离谱就说明原始 CRS 标错了。3.3 按区县统计路网密度路网密度是路网分析里最常用的指标算法是「区域内道路总长度 ÷ 区域面积」。这里有个坑地理坐标系下直接算长度得到的是度数不是米。必须先投影到投影坐标系。# 读取路网数据 road gpd.read_file(shandong_road.shp, encodingGBK) # 投影到 CGCS2000 3 度带山东大致在 39 带中央经线 117°E # EPSG:4547 是 CGCS2000 / 3-degree Gauss-Kruger CM 117E road_proj road.to_crs(epsg4547) county_proj county.to_crs(epsg4547) # 计算每条道路的长度米 road_proj[length_m] road_proj.geometry.length # 空间连接把道路按位置归属到区县 road_joined gpd.sjoin(road_proj, county_proj[[区县代码, geometry]], howinner, predicateintersects) # 按区县汇总道路总长度 road_length_by_county road_joined.groupby(区县代码)[length_m].sum().reset_index() road_length_by_county.columns [区县代码, 道路总长_m] # 计算区县面积平方公里 county_proj[area_km2] county_proj.geometry.area / 1e6 # 合并计算路网密度 result county_proj.merge(road_length_by_county, on区县代码, howleft) result[路网密度_km_per_km2] (result[道路总长_m] / 1000) / result[area_km2] # 输出密度最高的 10 个区县 print(result.nlargest(10, 路网密度_km_per_km2)[[区县代码, 路网密度_km_per_km2]])关键参数说明epsg4547是 CGCS2000 高斯克吕格 3 度带投影中央经线 117°E适合山东大部分地区。如果数据覆盖范围偏东如威海、烟台东部可以用 4548中央经线 120°E减少投影变形。predicateintersects表示道路与区县边界相交即算归属如果一条路跨两个区县会被分别计入两个区县这是合理的——路网密度本来就是按行政单元统计的。howinner会丢弃落在区县边界外的道路如果发现汇总后总长度比原始数据少很多检查是否有道路坐标偏移到了省界外。3.4 用公路网等级字段做分层统计公路网数据通常带等级字段按等级分层统计能看出路网结构。# 假设公路网有 等级 字段值为 高速、国道、省道、县道 highway gpd.read_file(shandong_highway.shp, encodingGBK) highway_proj highway.to_crs(epsg4547) highway_proj[length_m] highway_proj.geometry.length # 按等级汇总 level_stats highway_proj.groupby(等级).agg( 总长度_km(length_m, lambda x: x.sum() / 1000), 路段数(length_m, count), 平均段长_km(length_m, lambda x: x.mean() / 1000) ).reset_index() print(level_stats.sort_values(总长度_km, ascendingFalse))如果字段名不是「等级」而是拼音如dengji或英文road_level先用highway.columns.tolist()打印所有字段名确认。agg里对同一列用了三个不同聚合函数这是 pandas 的命名聚合语法输出列名就是等号左边的名字。平均段长这个指标能反映数据采集的粒度如果高速的平均段长只有 0.5 公里说明数据被切得很碎可能是按匝道口分段了做路径分析时要先合并。4. 避坑与排查SHP 处理中最容易翻车的五个地方4.1 中文乱码反复出现改了编码还是不对现象用 geopandas 读取时设置了encodingGBK但字段值仍然显示为乱码或问号。原因SHP 的编码问题可能出在 .dbf 文件头部的 language driver ID 上GDAL 有时会忽略 encoding 参数而优先读文件头。解决先用ogrinfo确认乱码是否存在如果 ogrinfo 正常而 Python 不正常用gpd.read_file(..., encodingGBK)的同时加SHAPE_ENCODINGGBK环境变量如果都不行用 dbfread 单独读属性表再手动挂接。4.2 空间连接后要素数暴增现象sjoin之后行数比原始道路数多了好几倍。原因一条道路与多个区县相交时会被复制多份这是空间连接的正常行为但如果不做后续聚合就会导致重复计算。解决明确分析目标——如果要统计每个区县的道路长度sjoin 后必须 groupby 聚合如果要保留道路完整属性用predicatewithin只保留完全落在区县内的道路或者用dissolve先合并区县再连接。4.3 面积计算出来是负数或极小值现象geometry.area算出来是 0.00x 这种数量级。原因数据还在地理坐标系度下没有投影。解决任何涉及长度、面积的计算之前必须to_crs到投影坐标系。山东用 EPSG:4547 或 4548全国范围用 Albers 等积投影EPSG:9822 或自定义。记住一个原则地理坐标系只用来存和传投影坐标系才用来算。4.4 道路网和行政区划边界对不上现象道路看起来偏移到了海里或者省界外。原因两个图层的坐标系不一致或者其中一个的 CRS 标错了。解决分别用gdf.crs打印两个图层的 CRS确认 EPSG 代码一致如果不一致统一转成同一个。如果 CRS 一致但仍有偏移检查是否一个用了 CGCS2000 一个用了 WGS84——两者在山东地区差几十米视觉上不明显但做精确分析时会有影响。4.5 大文件读取内存爆掉现象读取道路网 SHP 时进程被 kill 或报 MemoryError。原因SHP 格式单文件上限 2GB但要素数几十万时 geopandas 全量加载仍然吃内存。解决用gpd.read_file(..., rowsslice(0, 50000))分批读或者用 Fiona 的迭代器逐要素处理。如果只是做统计不需要几何运算用gpd.read_file(..., ignore_geometryTrue)只读属性表内存占用能降一个数量级。5. 进阶技巧用区划数据做路网可达性插值前面讲的都是「统计」这一章讲「分析」。路网可达性是个典型场景给定若干节点比如物流园区、医院计算每个区县到最近节点的路网距离。这个分析比直线距离靠谱得多但实现上有个关键选择——用路网距离还是用欧氏距离做插值。我的做法是先用区县质心做欧氏距离的快速估算筛出候选区县再对这些区县做精确的路网距离计算。这样能把计算量从 O(n×m) 降到 O(k×m)k 是候选区县数通常只有总数的三分之一。import numpy as np from shapely.ops import nearest_points # 假设 facilities 是设施点图层county_proj 是投影后的区县 facilities_proj facilities.to_crs(epsg4547) # 计算每个区县质心到最近设施点的欧氏距离 county_proj[centroid] county_proj.geometry.centroid county_proj[euclid_dist_m] county_proj[centroid].apply( lambda pt: facilities_proj.distance(pt).min() ) # 取欧氏距离最小的前 30% 区县做精确路网分析 threshold county_proj[euclid_dist_m].quantile(0.3) candidates county_proj[county_proj[euclid_dist_m] threshold].copy() # 对候选区县用最近设施点的路网距离替代 # 这里简化处理实际应用需调 pgRouting 或 networkx 做路网最短路径 candidates[road_dist_m] candidates[euclid_dist_m] * 1.4 # 迂回系数经验值 # 合并结果 county_proj county_proj.merge( candidates[[区县代码, road_dist_m]], on区县代码, howleft ) county_proj[final_dist_m] county_proj[road_dist_m].fillna( county_proj[euclid_dist_m] )迂回系数 1.4 是平原路网的常见经验值山东大部分地区适用。山区或水网密集区可能要调到 1.6 以上。这个系数的校准方法选几个已知路网距离的样本点用实际值除以欧氏距离取平均。如果手头有路网拓扑数据直接用 networkx 构建图做 Dijkstra 更准但构建图的时间成本不低几十万条路段大概要几分钟。出图时用matplotlib配contextily加底图把可达性用分级设色渲染出来import matplotlib.pyplot as plt fig, ax plt.subplots(1, 1, figsize(12, 10)) county_proj.plot(columnfinal_dist_m, cmapRdYlGn_r, legendTrue, axax, edgecolorgray, linewidth0.3) ax.set_title(山东省区县路网可达性到最近设施点) ax.axis(off) plt.tight_layout() plt.savefig(accessibility.png, dpi200, bbox_inchestight)cmapRdYlGn_r是红黄绿反转色带距离越近越绿符合直觉。edgecolorgray给每个区县加细边界线出图时层次更清楚。dpi 设 200 以上打印或放报告里不糊。最后说个血泪教训做可达性分析时千万别直接用区县质心代表整个区县。面积大的区县比如沂蒙山区那些质心可能落在无人区算出来的距离没有实际意义。我一般会按人口或 GDP 做加权质心或者干脆用格网做分析单元。这个坑我踩过不止一次希望帮到你。本文还有配套的精品资源点击获取

相关新闻

乌鲁木齐水系矢量数据:WGS84坐标系shp底图使用指南

乌鲁木齐水系矢量数据:WGS84坐标系shp底图使用指南

简介:本资源为乌鲁木齐市水系GIS矢量数据集,面向地理信息、城市规划、生态环境等领域的科研人员、GIS初学者及政府技术人员,用于支撑水文分析、洪水风险评估、生态廊道规划与空间可视化等实际应用。压缩包共17个文件,含2个shp&…

2026/10/13 17:19:25 阅读更多 →
MIMO-OTFS系统容量分析:Matlab仿真与高速场景性能评估

MIMO-OTFS系统容量分析:Matlab仿真与高速场景性能评估

高速移动场景下的通信质量衰减,是无线通信里最让人头疼的问题之一。基站发出的信号经过多径反射,到了高速移动的终端上,频偏、时延、多普勒扩展叠加在一起,传统的OFDM(正交频分复用)系统在这种信道环境下性能会剧烈下滑。MIMO-OTF…

2026/10/13 17:18:24 阅读更多 →
提示工程师饱和之后,AI落地才是真正的金矿

提示工程师饱和之后,AI落地才是真正的金矿

你可能也听说了,前两年被吹上天的“提示工程师”,现在成了招聘市场上最尴尬的角色之一。每一天都有无数人挤进生成式AI这个赛道,简历上写着“精通Prompt工程”“擅长调教大模型”,结果发现岗位早就从“高薪抢人”变成了“百里挑一…

2026/10/13 17:18:24 阅读更多 →

最新新闻

Service层命名规范:从见名知意到代码可维护性

Service层命名规范:从见名知意到代码可维护性

接手一个业务系统,我最怕看到的不是复杂算法,而是那种一打开就让人头晕的 Service 实现类。2000 行起步,方法名字从 process 到 handle 再到 doSomething,翻遍整个类也猜不出某个方法是干嘛的。命名这种事,看起来不影响…

2026/10/13 17:55:28 阅读更多 →
Windows内核模块枚举与隐藏原理深度解析

Windows内核模块枚举与隐藏原理深度解析

1. 这不是“找模块”,而是在内核内存里做一次精准外科手术“枚举和隐藏内核模块”——这八个字在安全研究、驱动开发或系统调试场景中,绝不是一句轻飘飘的技术术语。它背后是一整套对Windows内核运行时状态的深度观测与主动干预能力。我第一次在某高校实…

2026/10/13 17:55:28 阅读更多 →
Hibernate二级缓存Provider详解:从原理到选型与排坑

Hibernate二级缓存Provider详解:从原理到选型与排坑

被人突然问起“Hibernate的caching provider是什么”,我第一反应是:能问出这个词的人,多半已经看到配置文件里那一堆以hibernate.cache开头的键,但又没搞懂这些键到底在切换什么。这篇文章就把这个词拆开讲清楚,重点解…

2026/10/13 17:55:28 阅读更多 →
电能质量复合扰动识别:混沌集成决策树实战解析

电能质量复合扰动识别:混沌集成决策树实战解析

简介:这是一份面向电能质量复合扰动识别研究的MATLAB完整源程序包,对应知网论文《基于混沌集成决策树的电能质量复合扰动识别》,可作为电气工程、信号处理及机器学习方向的毕业设计或课题研究参考,帮助复现算法并开展对比实验。程…

2026/10/13 17:55:28 阅读更多 →
CentOS局域网DNS搭建:BIND9多域名权威解析实战

CentOS局域网DNS搭建:BIND9多域名权威解析实战

1. 为什么在CentOS上自建局域网DNS不是“多此一举”,而是刚需落地的第一步很多人看到“CentOS搭建局域网DNS”第一反应是:不就是改个/etc/resolv.conf?内网查个主机名用/etc/hosts不就完事了?我试过——在某高校实验室的物联网教学…

2026/10/13 17:55:28 阅读更多 →
ActiveMQ consumerCount精准获取与实战调优指南

ActiveMQ consumerCount精准获取与实战调优指南

1. 项目概述:为什么“获取消费者数量”是 ActiveMQ 运维与调优的黄金指标在某公司消息中间件团队的实际运维中,我接手的第一个紧急故障就和consumerCount直接相关——一个订单履约服务突然延迟飙升,下游库存扣减平均耗时从200ms暴涨到8秒。排…

2026/10/13 17:54:25 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →