SHP文件预处理三步法:坐标系声明、属性清洗与几何修复

发布时间:2026/9/16 13:57:48
SHP文件预处理三步法:坐标系声明、属性清洗与几何修复 简介本资源为伦敦城市空间分析专用GIS数据集面向地理信息、城市规划、公共安全等领域的研究者与高校师生支持交通网络建模、犯罪热点识别、多源空间叠加分析等实证研究。压缩包共26个文件含3个核心shp犯罪点位、交通线路、LSOA行政区划、4个dbf属性表、3个prj坐标系定义及配套shx、cpg、qpj等Shapefile标准组件另有CSV原始事件记录、QGIS工程文件.qgz和LSOA社会经济元数据.xlsx总大小14.3MB。已有318人学习下载数据覆盖2022年6月犯罪事件、伦敦全域交通设施及IMD2019贫困指数空间单元可直接导入QGIS或ArcGIS开展空间查询、核密度分析、缓冲区叠加与时空可视化附带完整元数据说明与项目结构便于快速启动城市治理类课题研究。1. 用伦敦交通与犯罪数据练手 GIS 分析SHP 文件不是“下载即用”而是要先验、再配准、最后建模你刚从某个开放数据平台下载了名为“London_Transport_Crime_2023.shp”的压缩包解压后看到 .shp、.shx、.dbf、.prj 四个文件双击 ArcGIS 或 QGIS 却提示“坐标系未知”“图层无法叠加”“点位漂移到北海去了”——这不是数据坏了而是 SHP 文件本身不携带完整空间语义它只是一份结构化地理要素容器。真正让伦敦地铁站落在正确街道旁、让犯罪热区精准套在行政区划内的是 PRJ 文件里那行GEOGCS[GCS_WGS_1984,DATUM[D_WGS_1984,...]]是 DBF 表中字段名是否匹配官方编码规范如 UK Police Force Code更是你手动校验拓扑关系时发现的 37 条道路线段未闭合、212 个犯罪点落在泰晤士河主航道中心线外 500 米缓冲区之外。本文面向已装好 QGIS 3.34 或 ArcGIS Pro 3.2 的实操者不讲 GIS 是什么只拆解如何把一包原始 SHP 变成可做空间连接、缓冲区分析、热力图渲染的可靠输入源。重点覆盖坐标系强制声明、属性表字段清洗、几何有效性修复三类高频卡点所有命令和参数均经伦敦 Open Data Portal 发布的 Transport for LondonTfL与 Metropolitan Police ServiceMPS2023 年公开数据实测。2. 验证并强制声明坐标系为什么伦敦 SHP 常见 WGS84 但必须显式指定SHP 文件的坐标系信息存储在 .prj 文件中但该文件极易丢失或被错误覆盖。当 QGIS 加载无 PRJ 的 SHP 时默认以“未定义坐标系”处理后续所有叠加分析都会失效。伦敦地区标准坐标系为OSGB 1936 / British National GridEPSG:27700而非全球通用的 WGS84EPSG:4326。若原始数据来自 TfL 官方 API 下载通常已含正确 PRJ但若经 Excel 导出再转 SHP、或从 PDF 地图截图矢量化则极大概率缺失或错配。2.1 用 ogrinfo 快速诊断坐标系状态# 检查 SHP 是否含有效 PRJ 及其内容 ogrinfo -so london_transport.shp # 输出关键行示例 # Layer SRS WKT: # GEOGCS[GCS_WGS_1984,DATUM[D_WGS_1984,SPHEROID[WGS_1984,6378137,298.257223563]],PRIMEM[Greenwich,0],UNIT[Degree,0.0174532925199433]] # 这表示当前为 WGS84 地理坐标系经纬度提示ogrinfo -so的-so参数表示“summary only”避免输出全部要素属性仅显示元数据。若输出中Layer SRS WKT为空或显示Unknown则必须人工赋值。2.2 强制重设坐标系不重投影QGIS 与 GDAL 双路径当确认数据实际采集于 OSGB 网格但 PRJ 错标为 WGS84 时需“声明真实坐标系”而非“转换坐标系”。错误做法是直接右键 → “设置图层 CRS”这会触发隐式重投影导致位置偏移正确做法是在 QGIS 中执行 CRS 声明推荐新手右键图层 → “属性” → “源”选项卡找到“坐标参考系统 (CRS)”下方的“指定图层 CRS”按钮图标为地球齿轮搜索EPSG:27700→ 选中“OSGB 1936 / British National Grid” → 点击“确定”此时图层右下角 CRS 显示变为EPSG:27700且地图视图自动适配英国本土投影用 GDAL 命令行永久修正适合批量处理# 将 london_transport.shp 的 CRS 声明为 EPSG:27700不改变几何坐标 ogr2ogr -a_srs EPSG:27700 london_transport_osgb.shp london_transport.shp # 验证结果 ogrinfo -so london_transport_osgb.shp | grep Layer SRS # 输出应为PROJCS[OSGB 1936 / British National Grid,GEOGCS[OSGB 1936,DATUM[Ordnance Survey Great Britain 1936...]]注意-a_srs参数是Assign SRS仅写入 PRJ 文件不修改 .shp 中的坐标值而-t_srs是 Transform SRS会重新计算所有点的 XY 值。对伦敦交通数据而言若原始采集使用 GPS 设备WGS84则需用-t_srs EPSG:27700转换若原始为 TfL 官方发布的 OSGB 格式却误标为 WGS84则必须用-a_srs声明。2.3 验证坐标系生效叠加权威底图比对声明 CRS 后必须验证是否真正对齐。加载英国 Ordnance Survey OpenData 的OS VectorMap District免费下载EPSG:27700作为底图将 transport 图层拖入同一画布若地铁站图标精准落在道路交叉口中心且公交线路沿实际路网走向则 CRS 正确若所有要素整体向西北偏移约 100 米典型 OSGB vs WGS84 偏差说明仍为 WGS84 坐标被强行解释为 OSGB若要素缩放后呈细长条状如道路变成平行线束说明误用了地理坐标系EPSG:4326叠加投影坐标系底图。此验证步骤不可跳过。伦敦市中心 1:10000 比例尺下10 米偏差即导致地铁站脱离真实出口位置直接影响后续缓冲区分析半径设定。3. 清洗属性表字段从犯罪统计表到可空间连接的标准化结构SHP 的 .dbf 表常含冗余字段、空值、类型混淆如本应为整数的crime_count存为文本、编码不一致如borough字段混用全称 “Westminster” 与缩写 “WSTMR”。这些缺陷会导致空间连接失败、分类渲染异常、SQL 查询报错。3.1 用 DBF 工具链识别字段问题# 查看字段结构与前 5 行数据需安装 dbfread pip install dbfread python -c from dbfread import DBF t DBF(london_crime.dbf, loadTrue) print(字段数:, len(t.fields)) for f in t.fields[:5]: print(f.name, f.type, f.length) for r in t.records[:3]: print({k:str(v) for k,v in r.items() if k in [AREA_NAME,OBSERVATION,YEAR]}) 典型问题输出字段数: 12 AREA_NAME C 50 # 字符型但应统一为小写且去空格 OBSERVATION N 10 # 数值型但部分值为 None 或 NULL YEAR N 4 # 年份字段但存在 2023.0 浮点格式3.2 用 QGIS 字段计算器批量清洗可视化可控对london_crime.shp图层启用编辑模式后在属性表中打开字段计算器目标操作表达式示例说明统一行政区名称为小写无空格lower(replace(AREA_NAME, , ))生成新字段borough_clean避免 City of London 与 cityoflondon 匹配失败将 OBSERVATION 转为整数空值置 0coalesce(to_int(OBSERVATION), 0)coalesce处理 NULLto_int强制转换防止后续 sum() 报错提取年份整数兼容 2023.0 和 2023floor(YEAR)floor函数确保浮点年份向下取整提示清洗后务必保存编辑并导出为新 SHP。原文件保留备份因字段计算器修改的是内存数据未保存则重启 QGIS 丢失。3.3 用 Python GeoPandas 实现自动化清洗适合多文件批量import geopandas as gpd import pandas as pd # 读取 SHP自动识别 CRS gdf gpd.read_file(london_crime.shp) # 清洗逻辑链 gdf[borough_clean] gdf[AREA_NAME].str.lower().str.replace( , ) gdf[crime_count] pd.to_numeric(gdf[OBSERVATION], errorscoerce).fillna(0).astype(int) gdf[year] gdf[YEAR].round(0).astype(int) # 删除原始冗余字段 gdf gdf.drop(columns[AREA_NAME, OBSERVATION, YEAR]) # 保存为新 SHP保留原始 CRS gdf.to_file(london_crime_clean.shp, driverESRI Shapefile)此脚本关键点errorscoerce将无法转数值的字符串设为 NaN再fillna(0)统一补零round(0)处理浮点年份比astype(int)更安全后者遇 NaN 会报错to_file()默认继承原 CRS无需额外指定crsgdf.crs。清洗后字段结构应为borough_cleanstr、crime_countint、yearint、geometryPoint/Polygon满足后续与行政区划 SHP 做sjoin的基本要求。4. 修复几何有效性解决“SHP 转 TXT 失败”“不能复制粘贴”背后的拓扑错误当尝试将伦敦道路 SHP 导出为 CSV/TXT如ogr2ogr -f CSV output.csv roads.shp时出现ERROR 1: Attempt to write non-linear geometry或在 QGIS 中选中要素后 CtrlC 无法粘贴根源往往是几何无效自相交线段、重复节点、面未闭合。SHP 格式本身不校验几何但下游工具GDAL/OGR、PostGIS、QGIS 渲染引擎在读取时会拒绝处理。4.1 用 QGIS Topology Checker 插件定位错误安装插件Plugins → Manage and Install Plugins → 搜索 “Topology Checker” → 安装启用配置规则规则类型must not have invalid geometries图层选择london_roads.shp点击 “Validate All”错误高亮显示红色圆点标记自相交点黄色虚线标出未闭合面边界常见伦敦道路数据错误A10 公路某段因 CAD 导入产生微小自环0.1 米泰晤士河支流岸线面未闭合首尾节点距离 2.3 米交叉路口处多条道路线段端点未 snap 到同一坐标导致网络分析断连。4.2 用 ogr2ogr SQLite SQL 一键修复命令行高效方案# 创建临时 SQLite 数据库并导入 SHP ogr2ogr -f SQLite london_roads_fixed.sqlite london_roads.shp # 在 SQLite 中执行几何修复GDAL 3.6 支持 ST_MakeValid sqlite3 london_roads_fixed.sqlite EOF UPDATE roads SET geom ST_MakeValid(geom) WHERE ST_IsValid(geom) 0; VACUUM; EOF # 导出修复后 SHP ogr2ogr -f ESRI Shapefile london_roads_fixed.shp london_roads_fixed.sqliteST_MakeValid()函数行为对自相交线分割为多个有效线段对未闭合面自动闭合添加首尾连线或转为多边形集合对悬垂线截断无效部分保留主体。注意ST_MakeValid可能改变要素数量一个无效面可能生成多个有效面故修复后需用ogrinfo -so london_roads_fixed.shp检查要素总数是否变化。若变化需人工核对新增要素是否合理。4.3 验证修复效果导出 TXT 与复制粘贴测试修复后执行导出测试# 成功导出为 CSV含 WKT 几何列 ogr2ogr -f CSV -lco GEOMETRYAS_WKT roads_wkt.csv london_roads_fixed.shp # 检查前 3 行是否含合法 WKT head -n 4 roads_wkt.csv # 应输出类似 LINESTRING (529876.12 181234.56, 529880.34 181238.78, ...)在 QGIS 中选中任意修复后道路要素 → CtrlC → 新建图层 → CtrlV应成功粘贴为新要素若仍失败说明存在非拓扑类问题如字段类型不支持剪贴板此时需检查 DBF 字段是否含二进制 blob。此步骤直接解决“shp转txt失败”“gis不能复制粘贴”等高频报错本质是让几何符合 OGC Simple Feature 规范。5. 构建可复用的空间分析流程从单次操作到自动化管道完成坐标系声明、属性清洗、几何修复后数据已具备分析就绪状态。但真实项目需反复处理新月度犯罪数据、新增地铁线路手动操作不可持续。本节提供基于 Makefile 的轻量级自动化管道适配 Linux/macOS 终端及 Windows WSL。5.1 定义标准化处理流程 Makefile# 文件名Makefile # 使用方式make all DATA_DIR./raw_data OUTPUT_DIR./cleaned DATA_DIR ? ./raw_data OUTPUT_DIR ? ./cleaned # 输入文件按伦敦数据命名惯例 TRANSPORT_SRC : $(DATA_DIR)/london_transport_2023.shp CRIME_SRC : $(DATA_DIR)/london_crime_2023.shp ROADS_SRC : $(DATA_DIR)/london_roads_2023.shp # 输出文件 TRANSPORT_OUT : $(OUTPUT_DIR)/transport_osgb_clean.shp CRIME_OUT : $(OUTPUT_DIR)/crime_clean.shp ROADS_OUT : $(OUTPUT_DIR)/roads_fixed.shp # 默认目标 all: $(TRANSPORT_OUT) $(CRIME_OUT) $(ROADS_OUT) # 步骤1坐标系声明OSGB $(TRANSPORT_OUT): $(TRANSPORT_SRC) echo ✅ 声明 Transport CRS 为 EPSG:27700 ogr2ogr -a_srs EPSG:27700 $ $ # 步骤2属性清洗Python 脚本 $(CRIME_OUT): $(CRIME_SRC) clean_crime.py echo ✅ 清洗 Crime 属性表 python clean_crime.py --input $ --output $ # 步骤3几何修复SQLite 方案 $(ROADS_OUT): $(ROADS_SRC) echo ✅ 修复 Roads 几何有效性 ogr2ogr -f SQLite roads_temp.sqlite $ sqlite3 roads_temp.sqlite UPDATE roads SET geom ST_MakeValid(geom) WHERE ST_IsValid(geom) 0; VACUUM; ogr2ogr -f ESRI Shapefile $ roads_temp.sqlite rm roads_temp.sqlite # 清理中间文件 clean: rm -f $(OUTPUT_DIR)/*.shp $(OUTPUT_DIR)/*.dbf $(OUTPUT_DIR)/*.shx $(OUTPUT_DIR)/*.prj5.2 编写 clean_crime.py 脚本适配不同年份字段#!/usr/bin/env python3 import argparse import geopandas as gpd import pandas as pd def main(): parser argparse.ArgumentParser() parser.add_argument(--input, requiredTrue) parser.add_argument(--output, requiredTrue) args parser.parse_args() gdf gpd.read_file(args.input) # 动态检测字段名兼容 TfL 与 MPS 不同发布格式 area_field [f for f in gdf.columns if area in f.lower() or borough in f.lower()][0] count_field [f for f in gdf.columns if count in f.lower() or obs in f.lower()][0] year_field [f for f in gdf.columns if year in f.lower()][0] gdf[borough_clean] gdf[area_field].str.lower().str.replace(r\s, , regexTrue) gdf[crime_count] pd.to_numeric(gdf[count_field], errorscoerce).fillna(0).astype(int) gdf[year] gdf[year_field].round(0).astype(int) gdf gdf.drop(columns[area_field, count_field, year_field]) gdf.to_file(args.output, driverESRI Shapefile) if __name__ __main__: main()5.3 一键运行与增量更新# 首次运行处理全部 make all DATA_DIR./data_july OUTPUT_DIR./july_clean # 仅更新新增的 8 月犯罪数据假设新文件为 london_crime_2023_08.shp cp ./new_data/london_crime_2023_08.shp ./data_july/ make $(OUTPUT_DIR)/crime_clean.shp DATA_DIR./data_july OUTPUT_DIR./july_clean此管道核心优势可重现每次make基于相同输入生成相同输出消除手动操作差异可审计Makefile 记录每步命令git diff可追踪清洗逻辑变更可扩展新增数据类型只需添加新 target 和对应脚本不破坏现有流程。当伦敦警方每月发布新犯罪统计时运维人员只需替换./raw_data/下文件执行make即得分析就绪数据集真正实现“数据进来模型出去”的闭环。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

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

尧图内容编辑团队

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

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

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

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

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

网站改版的5个关键决策

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

获取专属建站方案

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

立即免费咨询