☰
海南省五级行政区划SHP数据实战:从加载校验到WKT导出与渔网分割
2026/10/7 12:11:33 网站建设 项目流程

简介:本资源为2025年海南省五级行政区划矢量数据包,面向GIS从业者、城乡规划研究人员、高校师生及需要开展空间分析的技术人员,可解决省、市、县、乡镇(街道)、社区(村界)多层级地理数据获取难的问题。压缩包共38个文件,约61.51MB,以shp、shx、dbf、prj等Shapefile核心格式为主,辅以sbx、sbn空间索引及cpg、xml元数据文件,覆盖省、市、县、乡镇、村界五个层级,可直接导入ArcGIS、QGIS等软件进行地图绘制与空间分析。目前已有460人学习下载。数据层级完整、边界精度较高,适合用于宏观区域规划、土地利用分析、城乡扩张监测、灾害管理及基层精细化治理等场景,也可作为科研论文、课程作业与商业选址分析的基础底图,帮助读者快速搭建海南省地理空间研究的数据基础。

1. 2025海南省五级行政区划SHP数据:从村界到省界的矢量数据怎么落地

拿到一份「海南省五级行政区划SHP数据」的需求,通常不是单纯想收藏一个文件,而是要在自己的系统里把省、市、县、乡镇、村这五级边界跑通。海南的行政区划比较特殊:既有海口、三亚这类地级市,又有省直辖的县级市和县,还有大量乡镇和村界,层级嵌套不像内陆省份那么规整。这份SHP矢量数据的价值在于,它把五级边界统一到同一套坐标和属性结构里,能直接用于地图渲染、空间统计、选址分析、渔网分割、导出WKT做接口校验等场景。适合做GIS开发、自然资源信息化、城乡规划、物流区划的从业者。下面按「数据长什么样 → 怎么加载和校验 → 怎么转换和分发 → 坑在哪」的顺序,把可复现的路径讲清楚。

2. 五级行政区划SHP数据的结构与字段设计:先看懂再动手

2.1 五级层级在属性表里怎么表达

海南省五级行政区划SHP数据,常见做法是每个层级一个独立的Shapefile,或者合并成一个带层级字段的图层。独立文件的好处是加载快、字段干净;合并图层的好处是做空间叠加时不用反复切换数据源。我一般会先确认拿到的是哪种组织方式。

如果是独立文件,目录里通常会出现类似hainan_province.shp、hainan_city.shp、hainan_county.shp、hainan_town.shp、hainan_village.shp这样的命名。每个文件对应一级,属性表里至少要有行政区代码和名称两个字段。代码字段建议用字符串类型,不要用数值类型,因为行政区代码前几位可能以0开头,数值类型会丢前导零。

如果是合并图层,属性表里会多出一个层级字段,比如level或admin_level,取值1到5分别对应省、市、县、乡镇、村。这种结构在做渔网分割或者按层级筛选时更方便,一条SQL就能过滤出乡镇界。

提示:不管哪种组织方式,先打开属性表看字段名和字段类型,再决定后续处理脚本怎么写。字段名大小写不统一是常见问题,ArcGIS和QGIS对大小写的敏感度不一样。

2.2 坐标系与投影:海南数据必须确认的一件事

海南岛的经纬度范围大致在东经108°到111°、北纬18°到20°之间。如果拿到的是地理坐标系数据,通常是CGCS2000或WGS84,单位是度。如果要做面积统计、距离量算,必须投影到平面坐标系,否则算出来的面积是平方度,没有意义。

常见做法是投影到UTM 49N带,或者用海南当地的省级投影。CGCS2000的EPSG代码是4490,投影后的EPSG代码需要根据具体分带确定。我一般会在QGIS里先看图层属性里的CRS信息,再用「测量工具」拉一条已知距离的线做校验。

# 用geopandas检查SHP文件的坐标系和字段结构 import geopandas as gpd # 读取省级边界文件 gdf = gpd.read_file("hainan_province.shp") # 打印坐标系信息 print("CRS:", gdf.crs) # 打印字段名和类型 print("Columns:", gdf.columns.tolist()) print("Dtypes:\n", gdf.dtypes) # 打印前3行属性 print(gdf.head(3)) # 检查几何类型是否统一 print("Geom types:", gdf.geom_type.unique())

这段代码的逻辑是先确认坐标系,再确认字段结构,最后看几何类型。参数说明:gpd.read_file直接读取SHP文件,不需要额外驱动;gdf.crs返回坐标系对象,如果是None说明没有定义坐标系,需要手动指定;geom_type用来检查是否存在混合几何类型,比如面和线混在一起,这种情况在村界数据里偶尔出现,会导致后续空间操作报错。

如果发现坐标系是None,可以用gdf.set_crs(epsg=4490, inplace=True)补上。如果要做面积统计,再用gdf.to_crs(epsg=32649)投影到UTM 49N。

2.3 用QGIS做一次可视化校验

在写任何处理脚本之前,我习惯先用QGIS把数据拖进去看一眼。重点看三件事:边界有没有明显错位、村界有没有重叠或缝隙、属性表里有没有空名称。

操作步骤:打开QGIS,把五个层级的SHP文件依次拖入图层面板;右键每个图层选择「属性」→「源」,确认坐标系一致;用「识别要素」工具点击几个村界,看属性表里的名称和代码是否完整;最后打开「矢量」→「几何工具」→「检查有效性」,看有没有自相交或空几何。

如果发现村界之间有缝隙,常见原因是数据采集时用了不同的底图,或者做了简化处理。这种缝隙在做空间叠加时会变成空值区域,需要用「融合」或「修复几何」处理。如果发现重叠,通常是乡镇边界和村边界没有对齐,需要以村界为准做一次更新。

3. 把SHP用起来:加载、筛选、导出WKT和渔网分割

3.1 按层级筛选并导出乡镇和村界

拿到五级数据后,最常用的操作是按层级筛选。比如只想要乡镇界做人口统计,或者只想要村界做电商配送范围。用geopandas可以一行代码完成筛选。

import geopandas as gpd # 读取合并图层 gdf = gpd.read_file("hainan_admin_all.shp") # 按层级字段筛选乡镇(level=4)和村(level=5) town = gdf[gdf["level"] == 4].copy() village = gdf[gdf["level"] == 5].copy() # 检查筛选结果数量 print("乡镇数量:", len(town)) print("村数量:", len(village)) # 导出为新的SHP文件,指定编码避免中文乱码 town.to_file("hainan_town_only.shp", encoding="utf-8") village.to_file("hainan_village_only.shp", encoding="utf-8")

逻辑说明:先读取合并图层,再用布尔索引筛选。参数说明:level字段名需要根据实际数据调整,有的数据用admin_level或diji;encoding="utf-8"在导出时指定,避免中文名称变成乱码,ArcGIS打开时如果乱码,可以在QGIS里重新导出并指定GBK编码。

如果数据是独立文件,直接读取对应的SHP即可,不需要筛选。但要注意独立文件之间的行政区代码要能对应上,否则做空间关联时会匹配失败。

3.2 导出WKT用于接口校验和数据库入库

很多业务系统不直接读SHP,而是把边界转成WKT字符串存到数据库或传给前端。WKT的优点是纯文本、跨平台、容易做版本对比。从SHP导出WKT的常见做法是用geopandas的to_wkt()方法。

import geopandas as gpd # 读取村界数据 village = gpd.read_file("hainan_village_only.shp") # 确保坐标系是经纬度,WKT通常用经纬度存储 village = village.to_crs(epsg=4490) # 生成WKT字段 village["wkt"] = village.geometry.to_wkt() # 导出为CSV,只保留代码、名称和WKT village[["code", "name", "wkt"]].to_csv( "hainan_village_wkt.csv", index=False, encoding="utf-8-sig" ) # 打印一条WKT看格式 print(village["wkt"].iloc[0][:200])

逻辑说明:先把坐标系转成经纬度,因为WKT在数据库里通常按经纬度存储;然后用to_wkt()生成字符串;最后导出CSV。参数说明:encoding="utf-8-sig"带BOM头,Excel打开不乱码;to_wkt()默认保留足够精度,如果WKT太长,可以用to_wkt(rounding_precision=6)控制小数位数,6位大约对应0.1米精度,对行政区划足够。

注意:WKT字符串可能非常长,一个复杂的村界WKT可能超过10万字符。入库前要确认数据库字段类型是TEXT或CLOB,不要用VARCHAR(4000)。

3.3 用渔网分割做格网统计

渔网分割是行政区划数据的高频用法,比如把海南岛切成1公里×1公里的格网,统计每个格网落在哪个村,或者计算每个格网内的道路密度。常见做法是用QGIS的「创建网格」工具,或者用geopandas生成格网再做空间连接。

import geopandas as gpd from shapely.geometry import box import numpy as np # 读取省级边界作为范围 province = gpd.read_file("hainan_province.shp").to_crs(epsg=32649) # 获取边界范围 minx, miny, maxx, maxy = province.total_bounds # 生成1公里格网 cell_size = 1000 # 单位米 cols = np.arange(minx, maxx, cell_size) rows = np.arange(miny, maxy, cell_size) # 构建格网几何 from shapely.geometry import Polygon grid_cells = [] for x in cols: for y in rows: grid_cells.append(box(x, y, x + cell_size, y + cell_size)) grid = gpd.GeoDataFrame(grid_cells, columns=["geometry"], crs="EPSG:32649") # 只保留与海南岛相交的格网 grid = gpd.overlay(grid, province, how="intersection") # 与村界做空间连接,统计每个格网所属的村 village = gpd.read_file("hainan_village_only.shp").to_crs(epsg=32649) joined = gpd.sjoin(grid, village, how="left", predicate="intersects") # 统计每个村的格网数量 count_by_village = joined.groupby("name").size().reset_index(name="grid_count") print(count_by_village.head(10)) # 导出格网 grid.to_file("hainan_grid_1km.shp", encoding="utf-8")

逻辑说明:先把省级边界投影到UTM,获取范围;然后按1公里步长生成格网;用overlay裁剪到海南岛范围;再用sjoin把格网和村界关联起来。参数说明:cell_size可以根据需要改成500或2000;predicate="intersects"表示格网与村界有交集就算关联,如果只要完全落在村内的格网,改成predicate="within";groupby("name")按村名统计,如果村名有重复,改用行政区代码字段。

这个流程跑完后,每个格网会带上所属村的属性,可以进一步做人口、POI、道路的聚合统计。渔网分割的坑在于格网数量可能很大,海南岛按1公里切大约有3万多个格网,内存和计算时间要提前评估。

4. 格式转换与跨工具协作:DWG转SHP、SHP转TXT、SHP转3DTiles

4.1 DWG转SHP的可行路径

热搜词里出现「dwg转shp」,说明很多人手里有CAD格式的区划图,想转成SHP做GIS分析。DWG转SHP不是一键操作,因为DWG是图层+实体的结构,SHP是要素类+属性的结构。常见做法是先用QGIS或ArcGIS打开DWG,把需要的图层导出为GeoJSON或DXF,再转SHP。

在QGIS里的步骤:拖入DWG文件,QGIS会提示选择图层,勾选包含边界线的图层;右键图层选择「导出」→「要素另存为」,格式选ESRI Shapefile;在导出对话框里指定坐标系,如果DWG没有坐标系信息,需要手动指定海南当地的投影;导出后检查属性表,DWG里的文字标注不会自动变成属性,需要手动关联。

如果DWG里的边界是闭合多段线,导出后可能是线要素而不是面要素。需要先用「线转面」工具处理,或者用「几何修复」把闭合线转成面。这个环节最容易翻车,因为CAD里的线经常有微小缺口,导致转面失败。

4.2 SHP转TXT的两种用途

「shp转txt」通常有两种需求:一种是把坐标点导出成文本做外业核对,另一种是把属性表导出成文本做数据交换。如果是坐标点,可以用geopandas把几何的坐标序列写出来。

import geopandas as gpd # 读取村界 village = gpd.read_file("hainan_village_only.shp").to_crs(epsg=4490) # 提取每个村的质心坐标 village["centroid"] = village.geometry.centroid village["lon"] = village["centroid"].x village["lat"] = village["centroid"].y # 导出为TXT,制表符分隔 village[["code", "name", "lon", "lat"]].to_csv( "hainan_village_centroid.txt", sep="\t", index=False, encoding="utf-8" )

逻辑说明:先投影到经纬度,再算质心,最后导出。参数说明:sep="\t"是制表符分隔,方便导入Excel或其他工具;如果只要边界上的节点坐标,可以用village.geometry.boundary再遍历坐标。

如果是属性表导出,直接用to_csv或to_excel即可,注意中文字段用utf-8编码。

4.3 SHP转3DTiles的适用场景

「shp转3dtiles」一般出现在三维GIS项目里,想把行政区划边界拉伸成体块,在三维场景里做行政区划展示。这个转换不是标准GIS操作,需要借助三维工具链。常见做法是:先把SHP转成GeoJSON,再用Cesium ion或开源工具做白模拉伸,最后切成3DTiles。

如果只是做边界线在三维场景里的贴地显示,不需要转3DTiles,直接把SHP转成GeoJSON,用Cesium的GeoJsonDataSource加载即可。如果要做出有高度的行政区划体块,需要给每个面一个高度字段,再用工具做拉伸。这个流程对数据质量要求高,面必须闭合且不能自相交,否则拉伸会失败。

提示:SHP转3DTiles之前,先用「检查有效性」工具修复几何,确保每个面都是有效的。海南的村界数据如果来自不同来源,几何质量参差不齐,这一步不能省。

5. 避坑与排查:五级行政区划数据最常见的5个问题

5.1 中文属性乱码:现象是QGIS里名称显示正常,ArcGIS里变成问号

现象:在QGIS里打开SHP,村名显示正常;用ArcGIS打开同一个文件,中文全部变成乱码或问号。

原因:SHP文件的属性编码没有统一标准,QGIS默认按UTF-8解析,ArcGIS默认按系统编码解析。如果数据在导出时用了GBK,ArcGIS可能正常而QGIS乱码,反之亦然。

解决:在QGIS里重新导出一次,导出时在「编码」选项里明确选择UTF-8或GBK,根据目标工具调整。如果要在两个工具之间来回用,建议导出两份,一份UTF-8给QGIS,一份GBK给ArcGIS。或者把数据转成GeoPackage格式,GeoPackage对编码的支持更统一。

5.2 行政区代码前导零丢失:现象是代码从「460100」变成「4601」

现象:属性表里的行政区代码字段,原本是6位或9位,打开后变成了数值,前导零消失,或者位数不对。

原因:SHP的DBF字段类型如果是数值型,会丢失前导零。很多数据在生成时没有把代码字段设为字符串类型。

解决:用geopandas读取后,把代码字段强制转成字符串,再导出。如果已经丢失,需要从原始数据重新导出,或者在代码前补零。补零的逻辑要根据代码长度判断,比如6位代码补到6位,9位代码补到9位。

import geopandas as gpd gdf = gpd.read_file("hainan_admin.shp") # 强制转为字符串并补零到6位 gdf["code"] = gdf["code"].astype(str).str.zfill(6) # 重新导出 gdf.to_file("hainan_admin_fixed.shp", encoding="utf-8")

5.3 村界与乡镇界不套合:现象是村界超出乡镇界范围

现象:把村界和乡镇界叠加显示,发现有些村界超出了所属乡镇的边界,或者乡镇界内有空白区域没有村界覆盖。

原因:不同层级的数据来自不同采集批次,或者做了不同的简化处理。村界可能用了更精细的底图,乡镇界用了较粗的底图。

解决:以村界为准,用「融合」工具按乡镇代码把村界合并成乡镇界,替换原来的乡镇界。如果村界本身有缝隙,先用「修复几何」处理。这个操作会改变乡镇界的形状,需要和业务方确认是否可接受。

5.4 投影不一致导致面积算错:现象是面积统计结果差了几十倍

现象:用不同层级的SHP做面积统计,省级面积和市县面积之和对不上,或者面积数值明显偏大偏小。

原因:有的图层是地理坐标系(单位度),有的是投影坐标系(单位米),直接算面积会得到平方度或错误数值。

解决:统一投影到平面坐标系后再算面积。用gdf.crs检查每个图层的坐标系,用to_crs统一转换。海南数据建议统一到EPSG:32649(UTM 49N),面积单位是平方米。

5.5 渔网分割后格网数量爆炸:现象是脚本跑了几十分钟还没结束

现象:用1公里格网分割海南岛,脚本运行时间过长,内存占用飙升。

原因:格网生成时用了整个边界框的范围,包含了大量海域格网,导致格网数量远超实际陆地面积所需。

解决:先用省级边界做overlay裁剪,只保留与陆地相交的格网。或者先用clip把格网裁剪到陆地范围。另外,格网尺寸不要设得太小,1公里对村级统计通常够用,500米会导致格网数量翻4倍。

6. 进阶技巧:用空间索引加速五级数据叠加,以及一份可复用的校验清单

五级行政区划数据用久了,最耗时的操作不是加载,而是反复做空间叠加。比如把村界和POI做空间连接,或者把乡镇界和路网做叠加。数据量一大,没有空间索引的叠加会慢到让人怀疑人生。我一般会在加载后立刻建空间索引,geopandas底层用shapely,可以调用sindex属性。

import geopandas as gpd village = gpd.read_file("hainan_village_only.shp").to_crs(epsg=32649) poi = gpd.read_file("hainan_poi.shp").to_crs(epsg=32649) # 建空间索引 village.sindex poi.sindex # 用sjoin做空间连接,底层会自动用索引 joined = gpd.sjoin(poi, village, how="left", predicate="within") # 统计每个村的POI数量 poi_count = joined.groupby("name").size().reset_index(name="poi_count") print(poi_count.sort_values("poi_count", ascending=False).head(10))

逻辑说明:sindex是惰性构建的,第一次访问时生成,后续查询会复用。sjoin在底层会利用索引做候选筛选,比暴力遍历快几个数量级。参数说明:predicate="within"表示POI完全落在村界内才算,如果只要相交就算,改成intersects。对于海南这种数据量,村界大约几千个,POI可能几十万,建索引后连接时间通常在秒级。

另一个进阶用法是把五级数据做成层级树。每个村有唯一的行政区代码,代码的前几位对应乡镇、县、市、省。可以用代码前缀做聚合,不需要做空间叠加就能统计。比如村代码前6位是乡镇代码,前4位是县级代码。这种编码规则在国标里是统一的,用字符串切片就能实现层级汇总。

import pandas as pd # 假设村数据里有9位行政区代码 village = gpd.read_file("hainan_village_only.shp") # 提取乡镇代码(前6位)和县级代码(前4位) village["town_code"] = village["code"].str[:6] village["county_code"] = village["code"].str[:4] # 按乡镇汇总村的数量 town_summary = village.groupby("town_code").size().reset_index(name="village_count") print(town_summary.head()) # 按县汇总 county_summary = village.groupby("county_code").size().reset_index(name="village_count") print(county_summary.head())

这个方法的坑在于代码长度必须统一,如果有的村代码是9位,有的是12位,切片会出错。先用str.len()检查代码长度分布,再决定切片规则。

最后给一份我每次拿到新行政区划数据都会跑的校验清单,按顺序过一遍,能避开大部分翻车:

检查项检查方法通过标准
坐标系gdf.crs不为None,且与业务需求一致
几何类型gdf.geom_type.unique()只有Polygon或MultiPolygon
空几何gdf.geometry.is_empty.sum()结果为0
无效几何gdf.geometry.is_valid.all()结果为True
代码长度gdf["code"].str.len().unique()同一层级长度一致
名称空值gdf["name"].isna().sum()结果为0
层级数量gdf["level"].value_counts()与预期层级数一致

这份清单跑完,基本能确认数据可用。剩下的就是按业务需求做筛选、转换和叠加。我自己的习惯是每次拿到新数据先跑一遍这个清单,把结果存成一个文本文件,后面出问题可以回溯。希望帮到你。

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

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

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

立即咨询