2017县级行政区shp数据处理实践:编码、匹配与批量出图

发布时间:2026/10/9 21:29:53
2017县级行政区shp数据处理实践:编码、匹配与批量出图 简介这是一份1100万基础地理数据库中的2017年全国县级行政区划矢量数据以SHP格式封装边界信息面向地理信息系统从业人员、城乡规划与空间分析学习者。数据集采用1:100万比例尺内置县级行政界限及其配套文件适合用于行政区划制图、区域统计分析、多图层叠加分析等场景。压缩包共7个文件包括prj投影定义、dbf属性表、shp几何数据以及相关索引与元数据文件整体大小46.33MB结构清晰便于在ArcGIS、QGIS等平台直接使用。当前已有614人学习下载说明该数据在行政区划基础数据处理中具备一定实用价值。启用这套资源可获得可直接加载的县级边界矢量层配合原始属性字段可开展县域名称、代码检索与专题图制作同时投影与索引文件齐全能够保障常用GIS软件中的空间定位准确性和访问效率适合作为空间分析项目的基础底图数据。1. 这个shp数据是什么一次区划普查的低成本起点做行政区划相关分析的人大概率都遇到过这种尴尬领导突然要求出一张“全县所有乡镇边界图”或者要做某省近十年区划调整的演变对比而你手里只有一份现势性不保证、边界精度全看命的在线地图截图。这时候一份按县级行政区组织好的基础地理shp文件就是省掉两周手工活儿的底牌。标题里提到的“1100万基础地理数据库_2017县级行政区shp文件”本质上是一套以2017年全国县级行政区为单位的矢量边界数据集几何以面要素为主属性里带着区划代码和名称。它解决的核心问题很简单——当你需要做区域空间统计、制图、统计年鉴挂接或者历史区划比对时不再用自己从零描边界也不用靠在线瓦片凑合。适合的读者很明确GIS从业者、国土空间规划相关岗位、做农林和人口数据空间化的人以及所有被“找一份能用的县界数据”折磨过的数据民工。这份数据不是万能的它只是一个起点。它提供的是2017年那个时间断面上的县级行政边界框架精度和完整性取决于原始来源拿到手先做体检是必须的步骤。接下来从数据结构、加载方式、常用操作、踩坑记录到最后自动化出图完整走一遍。2. 拆开1100万数据的壳shp四个文件与字段编号规则2.1 为什么是shp而不是GeoJSON一个老格式的取舍逻辑2017年的基础地理数据选择Shapefile格式是当时数据生产链条的自然结果。Shapefile虽然被吐槽为“上世纪格式”但它到今天仍是国内数据交换的主流载体核心原因是兼容性。ArcGIS能用、QGIS能用、ogr2ogr能转、Python的pyshp和geopandas能直接读几乎没有GIS工具链会拒绝shp。相比GeoJSONshp对属性字段类型区分明确数值、文本、日期在制图和空间分析时少一层类型猜测相比File Geodatabaseshp不用装ArcGIS环境也能完整读写。所以拿到这份数据后第一件要做的事不是质疑为什么又是shp而是把shp的家族成员认全。一个完整的Shapefile不是一个文件而是一组同名文件的集合。.shp是空间几何本体.shx是几何索引.dbf是属性表.prj是投影信息。实际数据包里还可能混着.sbn和.sbx空间索引、.cpg字符编码标识。这组文件里任何一环缺失都会引发连锁问题丢了.shx部分软件打不开丢了.prj坐标系统变成未知丢了.cpg属性乱码可能立刻出现。因此拿到数据后的头5分钟直接在文件夹里把所有同名文件按后缀列一遍确认四件套齐全。ls -la *.shp *.shx *.dbf *.prj这条命令用来核对shp的四件套是否齐全。如果输出里缺了.prj说明该数据没有内嵌坐标参考定义后续需要手动指定如果缺了.dbf属性表无法读取这个数据基本废了一半。2.2 属性字段怎么看区划代码与名称的对应逻辑县级行政区shp的核心属性字段结构并不复杂常见设计是三个字段PAC行政区划代码、NAME县级名称、省/市名称字段外加一个面积字段。PAC字段是这份数据的灵魂——它是6位数字前两位是省级代码中间两位是地级代码后两位是县级代码。比如某个县的代码是21028221就是省级代码02是地级82是该县在序列里的位置。理解了这层结构后续所有按省筛选、按地市归类、与统计年鉴连接的操作全部可以围绕PAC做字符串截取来解决完全不需要依赖中文名称匹配。字段读取时有一个极易踩的坑dbf文件的中文字符编码。2017年的基础地理数据大多采用GBK编码保存中文字段而现代GIS软件默认读取UTF-8结果就是属性表打开后一片乱码。QGIS中可以在图层属性里手动指定编码为GBK但更稳妥的做法是先用Python把编码探出来。import chardet with open(county_2017.dbf, rb) as f: raw f.read(10000) result chardet.detect(raw) print(result[encoding])这段代码用chardet去探测dbf文件头部的编码类型。GBK编码的文件会输出类似GB2312或GBK的结果UTF-8则会输出utf-8。拿到结果后在QGIS的“数据源管理器”里直接将编码指定为该值就能避免属性表乱码。参数说明read(10000)只读取前10000字节这足以覆盖dbf结构头部和首批字段值速度很快如果整个文件读入内存再探测遇到几百兆级别的大dbf会白白浪费时间。chardet本身不是百分之百准确如果输出ascii而实际是中文数据可以再尝试强制指定gbk。3. 把2017县级边界正确加载到QGIS从编码到出图的三步3.1 最小可用加载流程坐标系与默认样式的一次成型QGIS是处理这份数据最顺手的工具免费且跨平台。加载shp的路径很简单但你直接拖进去大概率会得到两个不理想的结果一是属性表乱码二是面图层全部挤在地图角落或者缩成一团。前者是编码没指定后者是坐标系识别不准或投影设置不匹配。推荐的加载方式是在QGIS的“图层”菜单里选“添加矢量图层”然后在“数据源管理器”弹窗的“编码”下拉框里手动选择GBK前提是第2章探测出的结果是GBK系列。这一步做完属性表的中文就正常了。接着看右下角的坐标显示——确认状态栏的CRS标识是否指向某个CGCS2000系或地理坐标系。如果显示的是未定义右键图层属性在“源”选项卡里点击“为图层设置CRS”输入EPSG:4490CGCS2000地理坐标系或根据数据来源指定投影坐标系。import geopandas as gpd gdf gpd.read_file(county_2017.shp, encodinggbk) print(gdf.head()) print(gdf.crs)用geopandas读取的这行命令encodinggbk直接绕过乱码问题print(gdf.crs)会输出无坐标系或具体EPSG编号。如果输出为None后面所有投影转换操作前必须先补crs比如gdf gdf.set_crs(EPSG:4490)。参数说明encodinggbk只能解决属性表文字不影响几何坐标gdf.crs是geopandas读取.prj后自动生成的坐标参考描述。如果这个值是None而数据实际又是CGCS2000的经纬度后续做投影转换会导致错误的空间计算所以这一步做一个数值校验把全国县级数据读进来看最西的经度是否在73附近最东是否在135附近纬度区间在18到54之间粗略符合这个范围坐标系大概率是经纬度且位置正确。3.2 符号化与最小制图拿到图层后先做两件事加载成功不等于能直接出图。县级边界的数据几何质量参差不齐最常遇到的是两类现象相邻县的边界线重叠或者互相“咬合”不严以及某些县只有一条行政中心点坐标而边界缺失。后者在真正的shp数据里不常见但边界重合在原始数据集中几乎是惯例。为了快速检查几何质量先做两件事。第一件事是拓扑检查。QGIS的“处理工具箱”里找到“Check validity”检查几何有效性选择面图层运行。检查结果会产出一个无效图层列出所有自相交、折点重复的要素。对于县级数据轻微的自相交可以通过“修复几何”算法一键处理但如果错误量超过总要素数的5%就得考虑数据源本身质量不高后续分析可能受限。第二件事是做一层最简单的“范围核对”。把图层缩放至全图和美国或者欧洲的行政区划边界对比没有意义但可以和《中国行政区划简册》的县级数量做个数量比对——2017年全国县级行政区数量应在2800到2900之间含县级市、市辖区、县、自治县。如果加载后的要素总数偏差超过10%要么是数据合并过比如市辖区全部融掉了要么是切分过把乡镇数据错当成县级这个偏差会让后续所有基于要素计数的统计全部失准。print(gdf.shape) print(gdf.geom_type.value_counts())输出结果里行为要素个数列中POLYGON和MULTIPOLYGON的总数应该和预期县级数量一致。如果出现了POINT或者LINESTRING混入说明数据包里混进了非面要素用gdf gdf[gdf.geom_type.isin([POLYGON, MULTIPOLYGON])]过滤掉。4. 常用省县操作筛选、融合与业务表关联的实操4.1 按省级代码抽取目标范围字符串截取比边界框更可靠做分析时通常不需要全国数据只需要某个省或者某个市的县级图。按行政区划代码截取是最稳健的做法比用省名称匹配高几个量级——名称存在“省”字省略、历史简称差异等不确定因素代码是唯一稳定标识。target_province gdf[gdf[PAC].str.startswith(35)]这个操作把PAC字段以字符串形式处理截取前两位为35的县对应某省。需要注意PAC在dbf中可能是整型也可能是字符串型若是整型则需要先转字符串gdf[PAC] gdf[PAC].astype(str).str.zfill(6)。这个zfill的目的是把可能因首尾0被省略的短代码补齐到6位比如某县代码是1101直接读进来可能是1101或者11010zfill后能统一规整到正常编码格式。抽取出来后有多余的“飞地”时注意核对一下空间位置。比如边界外有一个孤岛状的小面要素PAC的省级代码依然是35但空间上悬在其他省份范围内。这不是数据错误而是真实的行政区飞地。是否需要保留取决于分析目的——做面积统计时保留飞地更准确做空间可视化时建议排除以免图形观感异常。4.2 县域融合到地市层级dissolve操作的边界精度隐患拿到县级数据后最常见的升级操作是把县级面融合为地市级面。QGIS里对县级图层使用“融合Dissolve”工具字段选地市代码。前提是属性表里存在地市代码字段或者可以现场从PAC中导出地市代码取PAC前4位就是地级代码代码相同的县归并。gdf[city_code] gdf[PAC].str[:4] city_gdf gdf.dissolve(bycity_code, aggfuncsum)这段代码先构造city_code字段再按该字段融合。aggfuncsum的作用是指定融合后的属性表里数值字段如何处理——面积字段可以用sum汇总而县名称字段需要靠别的策略保留或丢弃。如果不指定aggfunc非数值字段默认取第一个要素的值这在语义上往往是错的。融合后的边界精度是一个隐蔽坑。Dissolve工具处理相邻面时如果原始数据的边界线不重合常有1毫米级的缝隙融合结果可能会出现细长的空隙或重叠片。某开发者在某次处理跨省数据时融合后计算地市总面积发现比各县面积之和少了约3%追查后发现就是边界缝隙被工具按照“最小面积要素”规则舍掉了。解决方式有两个一是融合前先对相邻县做“消除缝隙”处理二是融合后做一步sliver多边形清理面积小于某个阈值的碎片面直接删除。一般阈值取该数据最小县级面积的1%再小的碎片大多属于处理误差。4.3 与统计年鉴数据关联代码匹配一劳永逸拿到2017年统计年鉴里的县域经济数据后最常用的操作是把表格join到shp属性表上做专题图。join的中文键不要选名称用PAC代码最稳。年鉴表格中的行政区划代码通常也是一列6位数字但注意Excel表格里这类代码常被“科学计数法”破坏——先检查代码列是不是文本格式建议在Excel中把该列强制设为“文本”再复制到新列操作。关联成功后还要做一个“未匹配置检查”。QGIS的join操作不会自动提示有多少记录没匹配上你可以通过查看属性表“未匹配”标记来感知。某次数据关联中一张常年更新的统计表里已经出现了2017年之后才设立的区划代码导致约30个县无法匹配。处理办法是两个方向查“代码变更对照表”或者按名称做第二通道匹配。一个相对省力的做法是保留一张近年区划调整对照表专门把新代码映射到2017年版本做完映射后再join一次。merged gdf.merge(stat_df, left_onPAC, right_oncode, howleft) print(merged[GDP].isna().sum())howleft保证左表shp全部保留右表缴费数据缺失的行保留为NaN。打印出的NaN数量就是未匹配的县数如果数量过大先去清洗右表的代码格式而不是急着怀疑shp数据有问题。5. 实践避坑编码错乱、边界飞地与旧数据残留5.1 属性乱码翻车dbf编码与图层文件被静默改写这是百分之百会遇到的问题不在第3章提前指定编码的几乎都会遭遇一次。现象是属性表里显示“锟斤拷”“鈥”之类的乱码串或者中文字段全部变成问号。原因是QGIS或ArcGIS在保存图层时如果是从乱码状态直接导出成新shp会把错误的编码信息一路带进新文件导致“修了源头下游仍然乱”。解决路径有两个第一在新项目里重新加载原始shp并立即指定GBK编码第二如果原文件已经被覆盖尝试用chardet探测当前dbf的编码类型若显示utf-8而内容仍乱码用iconv把dbf从GBK重新转码。iconv -f GBK -t UTF-8 county_2017.dbf county_2017_utf8.dbf这条命令会生成一个编码转换后的dbf副本。注意只有.dbf被转码.shp的几何不变所以需要同步把.shp、.shx连同新dbf一起命名成对应的同名文件族比如都叫county_2017_utf8然后再加载。实测这个方案对大量2017年左右生产的数据有效但转换后字段名的长度可能超出dbf规范要求如果报错就缩短字段名到10个字符以内。5.2 边界“黑线”与拓扑瑕疵县界和县界之间的缝隙做两个省的合并图时如果两个省各自的shp是从不同数据源拼的交界处会发现明显的错位甚至一条河的两岸分属于不同县且位置相差近百米。原因是两省的基础测绘数据来自不同生产批次坐标校正层级不同。这不是做错了什么是原始数据的“原罪”。应对方案有两种要严谨就回到更上级的数据源去获取统一生产的全国县级边界如果条件不允许只能做视觉层面的修整——将错位区域用QGIS的“节点工具”手工移动节点对齐但大规模错位时人工成本太高通常不如找替代数据源。另有一种很常见的县城边界问题县面和县面之间存在细长“缝隙”放大后能看到白色间隔线。这与黑线是同一种问题处理方式是用“消除”算法把面积低于设定阈值的缝隙面删除并分配给相邻要素。阈值的设置要谨慎如果原始数据精度是1:100万缝隙宽度可能只有数十米设置50米阈值即可但若设置过大会误删真实的细长县域比如某些峡谷型县的自然形状。5.3 2017版数据里的“已消失”县时间断面带来的区划问题拿到2017年版本最需要警觉的是时间断层。2017年之后一些县撤县设市、撤市设区当年的名称和代码在地图上是正常的但放到当前语境下就成了“错误信息”。比如某市下辖的某县后来被整体划入市辖区PAC代码已停用而用现在的统计年报去关联时找不到对应记录。这不是bug是数据自身的时效性。处理方案是维护一张“区划代码变更映射表”。在实际业务里我通常会在原shp的dbf表里增加两个字段code_2017原始编码和code_now当前有效编码。涉及变更的县code_now填最新代码未变更的县两列相同。这样在做历史分析时用code_2017在做当前数据关联时用code_now一份数据通吃两个场景。如果在一份统计表里出现了代码和名称均无法匹配的行就去核查该代码是否已废弃必要时按名称模糊匹配再人工复核。5.4 面积字段可能不可信投影和量算单位的双重陷阱很多县级shp自带一个面积字段但它的数值可能让你怀疑人生——有的单位是公顷有的是平方千米有的是平方米更隐蔽的是有的直接用地理坐标下的球面面积除以固定系数得到计算结果和真实地表面积有系统偏差。某次真实场景里一个县的面积字段值比测绘局的公开面积大了约7%追查后确认是数据生产方用Web Mercator投影算的面积而Web Mercator在高纬度地区面积误差巨大。可靠做法是拿到数据后重新用等面积投影计算一遍面积。推荐使用的投影是国内常用的CGCS2000 / 3-degree Gauss-Kruger zone或者Lambert等面积投影。地理坐标面要素不能用QGIS的默认字段计算器直接算$area要先“重投影”为等面积投影。gdf_area gdf.to_crs(EPSG:4490) gdf_area[area_calc] gdf_area.geometry.area / 1e6to_crs(EPSG:4490)将面要素转为CGCS2000地理坐标系geometry.area返回的单位是“度”对应的角面积不能直接用。这句代码只是为了演示语法真正用于计算面积时必须改用等面积投影例如EPSG:3426Albers等积投影适合全国量算。量算结果单位是平方米除以1e6得到平方公里以此为基准对比原字段偏差超过2%就果断弃用原字段。5.5 代码字段里的“脏字符”肉眼看不到的全角和空格行政代码字段中混入空格、全角数字、不可见字符的情况非常频繁。表现是看起来相同的两个代码无法匹配成功Pandas merge后匹配数量异常低。排查方法很简单打印该列的前几个值的长度和repr。print(gdf[PAC].head().apply(lambda x: repr(x)))输出中如果看到350102 这类尾部带空格或者全角数字就需要清洗。清洗代码为gdf[PAC] gdf[PAC].astype(str).str.replace( , ).str.replace( , ).str.strip()。其中第一个replace处理全角空格第二个处理半角空格strip清除首尾不可见字符。这个清洗步骤体力活不大但漏掉它会让匹配结果始终差那么几十个县。6. 进阶技巧用pygeopandas做全县批量专题图县级shp最常见的进阶价值是出专题图。传统做法是在QGIS里一页一页调整布局几十个县做下来不但慢还容易样式不统一。更可控的做法是直接写一个Python脚本用matplotlib批量输出一套风格统一的县级分布图。import matplotlib.pyplot as plt for code, row in city_gdf.iterrows(): fig, ax plt.subplots(figsize(8, 10)) city_gdf.plot(axax, edgecolorwhite, linewidth0.2, color#e6e6e6) row.geometry.boundary.plot(axax, edgecolor#333333, linewidth0.8) ax.set_title(row[city_name] 县域分布, fontsize14, fontpropertiesfont) ax.axis(off) plt.tight_layout() plt.savefig(foutput/{row[city_name]}.png, dpi300) plt.close()这段代码按地市维度循环先用浅色渲染全地市的面再把当前地市的边界加粗描深最终输出带标题的底图。iterrows()按行取出数据row.geometry.boundary提取边界线几何对象dpi300保证印刷可用plt.close()不可省略否则连续生成几十张图后Python进程内存会涨到几GB。中文字体需要在绘图前先设置常规做法是加一行plt.rcParams[font.sans-serif] [SimHei]否则标题里的中文会变成方块。如果对出图的质量有更高要求把配色、标注点、比例尺和图例纳入这个脚本即可。这个脚本跑一轮全部地市只用数秒到十几秒相比手工出图节省的时间是数量级的。每次跑完图我都会做最后一道检查——随机抽三张图打开后手动比对县级边界的位置和数量确认和原数据没有偏差。另外可以把这个数据做成一个长期维护的内部底图工具。把2017年县级边界和每年更新的省市统计表放一起在QGIS里做成一个固定的“模板工程”后续新进来的同事可以直接用模板加载图层和样式不用每次从头折腾编码和坐标系。这是对一份基础地理数据最有价值的使用方式——让它成为后续所有空间分析的底座而不是一次性用完就丢的临时素材。希望这篇拆解能帮你在面对这类shp数据时少走弯路把时间花在分析本身而不是与数据格式搏斗上。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询