简介这份资源是2017年中国县级行政区划的矢量边界数据集基于1:100万比例尺的1100万基础地理数据库整理面向从事GIS分析、城市规划、人口统计、灾害评估等工作的技术人员与研究者可用于大范围空间叠加与制图。压缩包共7个文件约46.33MB以SHP矢量格式为核心配套DBF属性表存储县名与代码PRJ定义CGS_WGS_1984坐标系SHX、SBN、SBX等索引文件提升检索效率XML则记录元数据信息整体结构完整、开箱即用。目前已有614人学习下载。借助这套精细的县级行政边界读者可将其与人口密度、地形、气候等数据叠加快速完成区域统计、专题制图与空间模式挖掘为规划决策提供可靠的地理底图支撑。1. 1100万基础地理数据库里的县级行政区 shp它到底是什么谁该把它当回事如果你手头拿到一份标注“1100万基础地理数据库_2017县级行政区shp文件”的数据第一反应大概率不是兴奋而是犯嘀咕这跟网上随手能下的全国区划 shp 有啥区别值不值得花时间清洗入库。先说结论1100万指的是比例尺 1:1,000,000属于中小比例尺的基础地理数据库一套完整的库通常按要素分层组织县级行政区只是其中“政区与境界”这一层。2017 这个年份意味着它的行政区划快照停在那一年之后发生的撤县设市、区划调整它一概不知。它解决的核心问题是当你需要一套全国范围、拓扑相对干净、属性字段规整的县级面数据做底图、做统计挂接、做空间汇总时它比很多来路不明的 shp 靠谱。适合谁做全国尺度专题制图、做人口经济数据空间化、做流域与行政区叠加分析的人。如果你只关心某一个市甚至某一个县这份数据的分辨率可能不够用别硬上。2. 先搞懂 1100万县级行政区 shp 的字段与坐标再谈怎么用2.1 打开文件先看这三样坐标系、字段、几何类型拿到 shp 别急着往 ArcGIS Pro 里拖先确认三件事顺序不能乱。第一是坐标系1100万基础地理数据库常见做法是地理坐标系 CGCS2000单位是度不是米。你要是直接拿它算面积得到的是平方度毫无意义。第二是字段结构县级行政区层一般会有行政区代码、名称、上级代码这类属性但不同来源的库字段命名差异很大有的叫 XZQDM有的叫 ADCODE得先看一眼再写代码。第三是几何类型县级行政区是面但偶尔会遇到 MultiPolygon比如沿海县带岛屿处理时要注意。用 Python 的 geopandas 快速体检比在桌面软件里点来点去快得多import geopandas as gpd # 读取 shp注意 encoding 参数中文属性乱码多半是这里没设对 gdf gpd.read_file(county_2017.shp, encodingutf-8) # 看坐标系 print(CRS:, gdf.crs) # 看字段名和类型 print(gdf.dtypes) # 看几何类型分布 print(gdf.geom_type.value_counts()) # 看前几行属性 print(gdf.head())这段代码的逻辑是先建立数据认知再动手。encodingutf-8是关键很多老库用 GBK读出来属性全是问号换成encodinggbk再试。gdf.crs如果返回 None说明 shp 丢了 prj 文件你得手动指定坐标系否则后续所有空间操作都是错的。geom_type里如果出现 GeometryCollection说明有脏几何得先修复。2.2 投影转换为什么算面积前必须换到投影坐标系地理坐标系下做缓冲区、算面积、算长度结果都是错的这是新手最容易翻车的地方。1100万数据做全国分析常用的是 Albers 等积投影因为它能保证面积不变形。转换代码如下# 从地理坐标系转到 Albers 等积投影中央经线 105 度双标准纬线 25 和 47 gdf_proj gdf.to_crs(projaea lat_125 lat_247 lat_00 lon_0105 x_00 y_00 datumWGS84 unitsm no_defs) # 现在算面积才是平方米 gdf_proj[area_km2] gdf_proj.geometry.area / 1e6 print(gdf_proj[[NAME, area_km2]].head())参数说明lat_1和lat_2是双标准纬线中国常用 25 和 47能覆盖大部分国土lon_0105是中央经线大致在中国中部unitsm保证输出单位是米。如果你只做某一个省中央经线可以改成该省中心经度变形更小。转完之后面积字段才有物理意义拿它跟统计年鉴的县域面积对一下差太多说明投影或数据本身有问题。2.3 属性挂接把统计表格拼到 shp 上的正确姿势县级行政区 shp 最大的用途之一是挂接统计数据比如 GDP、人口。挂接的关键是行政区代码要能对上。常见坑是代码类型不一致shp 里是字符串Excel 里是数字直接 merge 全变 NaN。做法是两边都转成字符串再拼import pandas as pd # 读统计表行政区代码列强制为字符串 stats pd.read_excel(county_stats.xlsx, dtype{行政区代码: str}) # shp 里的代码列也转字符串去掉可能存在的空格 gdf[XZQDM] gdf[XZQDM].astype(str).str.strip() # 左连接保留所有县级单元 merged gdf.merge(stats, left_onXZQDM, right_on行政区代码, howleft) # 检查有多少没匹配上 print(未匹配数量:, merged[行政区代码].isna().sum())逻辑说明dtype{行政区代码: str}防止 pandas 把带前导零的代码读成数字。str.strip()处理肉眼看不见的空格。howleft保证 shp 的几何不丢。未匹配数量如果很大要么是代码版本不一致要么是 2017 年之后区划变了这份数据对不上新表这时候你得找区划变更对照表而不是硬凑。3. 用 1100万县级 shp 做空间分析从筛选到叠加的完整链路3.1 按属性筛选目标县再按位置筛选流域范围实际项目里很少直接用全国数据都是先缩小范围。比如你要研究塔里木河流域涉及的县思路是先按流域边界做空间筛选再按属性挑县。这里涉及两个操作属性筛选和空间筛选。# 属性筛选挑出某几个省的县 target gdf_proj[gdf_proj[省代码].isin([65, 63])] # 空间筛选用流域边界裁剪得到流域内的县 basin gpd.read_file(tarim_basin.shp).to_crs(gdf_proj.crs) counties_in_basin gpd.overlay(target, basin, howintersection) # 按面积占比判断哪些县主体在流域内 counties_in_basin[ratio] counties_in_basin.geometry.area / counties_in_basin[area_km2] / 1e6 main_counties counties_in_basin[counties_in_basin[ratio] 0.5]参数说明isin里的代码是省级行政区代码前两位65 是新疆63 是青海按需替换。overlay的howintersection表示求交集会切碎几何所以后面用面积占比还原“哪些县主体在流域内”。ratio 0.5是经验阈值低于这个值的县可能只有边角被流域碰到纳入分析会引入噪声。这一步做完你就得到了一份干净的、针对特定流域的县级单元列表。3.2 用渔网分割 shp把县级面切成规则格网做统计有时候你需要把县级行政区切成更小的格网比如做人口密度格网化。渔网分割 shp 是高频操作ArcGIS Pro 里有工具但用 Python 更可控。思路是先给每个县生成渔网再跟县面求交。import numpy as np from shapely.geometry import box def make_fishnet(gdf, cell_size10000): 给每个要素生成 cell_size 米边长的渔网并求交 results [] for idx, row in gdf.iterrows(): minx, miny, maxx, maxy row.geometry.bounds # 生成格网中心点 xs np.arange(minx, maxx, cell_size) ys np.arange(miny, maxy, cell_size) cells [box(x, y, x cell_size, y cell_size) for x in xs for y in ys] fishnet gpd.GeoDataFrame(geometrycells, crsgdf.crs) # 只保留与县面相交的格网 clipped gpd.overlay(fishnet, gpd.GeoDataFrame([row], crsgdf.crs), howintersection) clipped[county_code] row[XZQDM] results.append(clipped) return pd.concat(results, ignore_indexTrue) grid make_fishnet(gdf_proj.head(5), cell_size10000)逻辑说明bounds拿到每个县的外包矩形np.arange按步长生成格网坐标box造矩形。overlay求交后每个格网只保留落在县内的部分。cell_size10000是 10 公里格网全国尺度常用 1 公里到 10 公里看你的数据量和精度需求。这个函数对全国数据会很慢实际用的时候建议先按省拆分再并行或者直接用 PostGIS 的ST_SquareGrid效率高一个量级。3.3 导出与格式转换shp 转 GeoJSON、KML 和 3D Tiles 的取舍做完分析要交付格式选择有讲究。shp 字段名限制 10 个字符中文支持差导出 GeoJSON 更通用要给非 GIS 人员看KML 在 Google Earth 里直接打开要做三维可视化shp 转 3D Tiles 是另一条链路。# 导出 GeoJSON注意 ensure_asciiFalse 保留中文 merged.to_file(county_merged.geojson, driverGeoJSON, encodingutf-8) # 导出 KML需要先转成 EPSG:4326 merged.to_crs(EPSG:4326).to_file(county.kml, driverKML)参数说明GeoJSON 用encodingutf-8KML 必须用 WGS84 经纬度否则 Google Earth 里位置会偏。shp 转 3D Tiles 不是 geopandas 能直接干的常见做法是先把 shp 转成 GeoJSON再用 Cesium 的工具链或专门转换器处理注意高度字段要单独指定否则所有建筑贴地。如果你的数据只是行政区面没有高度信息转 3D Tiles 意义不大不如直接发布成矢量切片。4. 避坑与排查1100万县级 shp 处理中最容易翻车的 5 个地方4.1 中文属性乱码改 encoding 没用怎么办现象读 shp 后属性表里中文全是乱码换了几种 encoding 都不对。原因shp 的 dbf 文件编码不是标准 UTF-8 或 GBK可能是 GB2312 甚至更老的编码或者文件本身被二次编辑过。解决先用gpd.read_file不带 encoding 读一次看乱码规律再用chardet检测 dbf 文件编码实在不行用 QGIS 打开QGIS 的编码识别更宽容在里面重新导出为 UTF-8 的 GeoJSON再进 Python 处理。血泪经验是别在编码上死磕转一道手往往更快。4.2 面积算出来跟年鉴对不上差了好几倍现象投影转换后算的县面积跟统计年鉴差 2 到 3 倍。原因大概率是投影参数不对或者原始数据本身是 1100万这种小比例尺几何经过了综合简化面积精度本来就有限。解决先确认投影参数中国全国用 Albers中央经线 105再拿一个已知面积的县做基准测试如果还是差很多接受这份数据不适合做精确面积统计它更适合做位置参考和空间关系分析。要精确面积用更大比例尺的数据。4.3 merge 之后行数变多几何重复了现象挂接统计表后原本 2800 多个县变成了 3000 多行。原因统计表里有重复的行政区代码或者 shp 里同一个代码对应多个几何要素比如飞地。解决merge 前先stats.drop_duplicates(subset[行政区代码])shp 这边用dissolve按代码合并几何。如果确实有飞地需要保留那就接受多行但统计值挂接时要注意别重复计算。4.4 用 overlay 裁剪后边界上出现碎屑多边形现象流域裁剪县级 shp 后结果里有很多面积几乎为零的碎多边形。原因两个数据层的边界不完全重合叠加时产生拓扑碎片。解决裁剪后按面积过滤gdf[gdf.geometry.area 阈值]阈值根据你的最小关注单元定比如 1e6 平方米。更彻底的做法是裁剪前先做一次buffer(0)修复几何或者用snap把边界对齐。4.5 导出 KML 后 Google Earth 打不开或位置偏移现象KML 文件生成了但 Google Earth 里要么报错要么图形跑到海里去了。原因坐标系没转成 WGS84或者几何有自相交。解决导出前强制to_crs(EPSG:4326)并用gdf.geometry.is_valid检查无效的用buffer(0)修复。另外 KML 对字段名也有要求中文字段名可能被截断导出前把字段名改成英文。5. 把 2017 县级 shp 用出长期价值版本管理与自动化更新这份数据是 2017 年的快照但你的项目可能持续好几年。我一般会做两件事让它不过期。第一是建立区划变更对照表把 2017 年之后撤县设市、改名、调整隶属的条目手工维护成一张 CSV每次挂接统计前先跑一遍对照把旧代码映射到新代码。第二是把整个处理链路脚本化从读取、投影、挂接、裁剪到导出写成一个可重复执行的 pipeline数据更新时只换输入文件参数不动。# 区划变更对照表示例结构 # old_code, new_code, change_type, change_year # 130000, 130100, 撤县设区, 2018 def apply_code_mapping(gdf, mapping_csv): mapping pd.read_csv(mapping_csv, dtypestr) gdf[XZQDM] gdf[XZQDM].astype(str) # 用 map 做替换没有映射的保留原值 gdf[XZQDM_NEW] gdf[XZQDM].map( dict(zip(mapping[old_code], mapping[new_code])) ).fillna(gdf[XZQDM]) return gdf这段代码的逻辑是用字典映射做代码替换fillna保证没变更的县不受影响。参数上mapping_csv要维护好变更年份做时间序列分析时按年份筛选映射关系别一股脑全替换。验证方法是替换后统计代码数量跟最新区划代码表对一遍数量对不上就说明映射有遗漏。最后一个习惯每次处理完 shp我都会把中间结果存成 GeoPackage 而不是 shp因为 GeoPackage 单文件、支持长字段名、支持中文、支持多图层比 shp 省心太多。1100万这份数据本身质量不错但它的价值取决于你怎么管它、怎么接后续数据。别把它当成一次性下载完就扔的素材把它当成一个需要维护的基础图层你的项目会少很多返工。希望帮到你。本文还有配套的精品资源点击获取