首页 / 资讯中心 / 文章详情

上海2020年POI矢量数据解析:shp、DEM与GIS清洗实战

上海2020年POI矢量数据解析:shp、DEM与GIS清洗实战 ★ FEATURED ARTICLE
简介上海市2020年POI矢量数据集是一份面向GIS研究者、城市规划人员及地图开发者的综合性地理信息数据包涵盖医疗保健、住宿服务、商务住宅、科教文化、风景名胜等多类兴趣点POI并附带30米分辨率数字高程模型DEM与区县级行政区划边界适合用于地形模拟、商业选址、公共服务设施分布评估及城市空间结构分析等场景。压缩包内共126个文件总大小80.65MB以15个shp矢量文件及其配套dbf属性表、prj投影定义、sbn/sbx空间索引为主辅以14个xlsx表格文件便于非GIS用户直接查看统计另有tif格式DEM高程栅格及tfw、ovr等辅助文件。数据同时提供shp与Excel两种形态既满足ArcGIS、QGIS等专业平台的空间分析与制图需求也方便业务人员快速检索地址、分类等属性信息。目前已有815人学习下载是开展上海地区多源地理数据融合与专题制图的实用基础资料。1. 上海2020年POI矢量数据集这份压缩包里到底装了什么做城市分析、商业选址或者区域评估的人大概率经历过这种局面想要一份覆盖全市的POI点位数据打开地图平台挨个爬跑断 IP 还被反爬卡脖子费半天劲拿到手又是加密的 Excel 表格或者字段残缺的 CSV。这份上海市 2020 年 POI 矢量数据集解决的就是这个「找数据比做分析还费劲」的问题。压缩包把三类常用数据打包在了一起shp 格式的 POI 矢量面/点数据、Excel 格式的 POI 台账、30 米分辨率的 DEM 高程栅格外加行政区划边界。对做 GIS 可视化和空间统计的从业者来说这是一份拆开即用的基础数据包省去的是数据获取和预处理最头疼的那一两个月。下面我按拆包、加载、清洗、用 DEM、踩坑这个顺序把这份资源的完整使用过程捋一遍。2. 解压与格式拆解7z、shp、excel 三类文件的读取路径2.1 先过 7z 这一关常见解压失败与命令行思路拿到的是一个 .7z 后缀的压缩包比 zip 的压缩率高但踩坑概率也高。最常见的翻车现场是拿老版本 WinRAR 双击解压中途报「数据错误」或者解出来一堆 0 字节文件。原因很简单7z 格式的固实压缩特性在分块解压时对版本要求更敏感。我一般直接用 7-Zip 官方版解压右键 → 提取到当前目录就行但如果你是在 Linux 服务器上处理命令行更稳# 安装 7zip 命令族发行版不同包名略有差异 sudo apt install p7zip-full # 解压整个归档-o 后面指定输出目录注意冒号与路径之间没有空格 7z x Shanghai_POI_2020.7z -o/data/geo_data/逻辑说明7z x保留压缩包内的目录结构-o指定输出的全路径忘写这个参数默认解到当前目录散文件容易和已有数据混在一起。参数上有两个习惯一是加-y覆盖已存在的同名文件适合重跑脚本二是不加-y保留手动确认机会防止误覆盖。解压过程中如果出现CRC Failed大概率是压缩包下载不完整别浪费时间修复重新下载比折腾恢复快。解压完成后你会看到至少四类东西POI_shp/矢量数据目录、POI_excel/表格台账目录、DEM/高程栅格、District/行政区划矢量。这是这份资源比较良心的点——分类目录不是堆在一起的乱文件。2.2 看清 shp 的本质不是单文件是一组文件的合称很多人拿到 shp 数据后只拷贝.shp后缀那个文件发给别人这是最容易翻车的操作。Shapefile 格式在技术上是一组文件的集合至少包含三个核心成员主文件.shp存储几何坐标索引文件.shx存储几何位置偏移量属性表.dbf存储字段属性。除此之外还可能带.prj坐标系描述、.cpg编码声明、.sbn/.sbx空间索引等附属文件。缺了.dbf属性表是空的缺了.prj坐标系信息丢失后续叠加分析会出现位置偏移的隐患。一份完整的 shp 集合拷贝时至少要带上.shp/.shx/.dbf/.prj这四个文件。2.3 Excel 格式 POI 的正确读法Pandas 与编码问题Excel 格式的POI数据一般用来做常规的表格处理、透视统计或给不会用 GIS 的同事做报表。但这个环节有一个非常隐蔽的坑.xlsx用的是 XML 结构读取时不会暴露编码问题但如果你用 WPS 或老版本 Office 另存过一次.xls再读进来的中文字段容易出现乱码。用 Python 读 Excel 格式 POI 的常见写法是import pandas as pd # 读取 Excel 格式 POIsheet_name 指定为明细表 poi_df pd.read_excel( POI_excel/shanghai_poi_2020.xlsx, sheet_namePOI, dtype{POI_ID: str, ADCODE: str} ) # 打印列名和行数确认读取完整 print(poi_df.columns.tolist()) print(poi_df.shape)逻辑说明dtype参数把 ID 和行政区划代码强制设为字符串否则POI_ID以数字开头时Pandas 会自动解析成 int64前导零丢失。该参数在此类数据读取中尤其重要因为区划代码、POI 编号这类字段本来就是文本标识不是数值。列名清单打印出来之后先核对有没有缺列再继续清洗。3. shp 格式 POI 的加载与清洗从 ArcGIS 到 Python 的完整链路3.1 ArcGIS 直接加载与属性表识别如果你用的是 ArcMap 10.8 或 ArcGIS Pro直接在 Catalog 中连接到 POI_shp 目录把对应图层的 shp 文件拖进内容列表。加载后先做两件事右键图层 → 打开属性表确认记录数和字段数再右键 → 属性 → 源确认坐标系。因为这份包里同时有 POI 和行政区划两个 shp坐标参考如果不一致后续空间连接会静默出错或者出现图层偏移到海里的现象。ARCGIS 中加载 shp 后如果字段名出现乱码比如本该是name却显示成乱符号属于.cpg编码声明丢失一般解决方式是使用 QGIS 打开再重新导出。3.2 Python 读写 shpGeoPandas 是效率首选不想依赖桌面 GIS 软件时GeoPandas 是处理 shp 最顺手的库。它的 DataFrame 结构让筛选、分组、空间连接都能用熟悉的 Pandas 思维完成。这里我一般会用两步先读取 shp 看结构再按行政区划代码筛选出目标区域的数据。import geopandas as gpd # 读取 POI 点图层 poi_gdf gpd.read_file(POI_shp/shanghai_poi.shp, encodingutf-8) # 读取行政区划面图层 district_gdf gpd.read_file(District/shanghai_district.shp, encodingutf-8) # 查看坐标系和记录数确认加载成功 print(poi_gdf.crs) print(poi_gdf.head())逻辑说明encoding参数在 shp 读取中经常被忽略但上海市的数据字段名通常带中文像名称、地址、区县如果.cpg文件缺失或者损坏encodingutf-8能保证中文属性正常显示。坐标系crs属性返回的是投影信息如果 POI 是EPSG:4326经纬度而行政区划是EPSG:3857Web 墨卡托两者叠加前必须统一到同一个坐标系。3.3 坐标统一与 POI 分类字段清洗这份资源里 POI 的字段设计一般会比较规整通常包含POI_ID、名称、大类、中类、小类、地址、区县、经度、纬度。但规整不等于可以直接用常见的两个毛病一是经纬度字段是字符串格式并且可能有空格二是「大类」字段存在多个值比如某个银行网点同时被标了「金融」「生活服务」两个类别。清洗时按以下思路处理import pandas as pd # 清洗经度纬度列去空格后再转 float poi_gdf[经度] pd.to_numeric(poi_gdf[经度].astype(str).str.strip(), errorscoerce) poi_gdf[纬度] pd.to_numeric(poi_gdf[纬度].astype(str).str.strip(), errorscoerce) # 类别字段只取主类别分隔符常见的有中文顿号或斜杠 poi_gdf[主类别] poi_gdf[大类].str.split(、|/).str[0] # 删除经纬度缺失的记录静默过滤而不是报错中断 poi_gdf poi_gdf.dropna(subset[经度, 纬度]) print(poi_gdf[主类别].value_counts().head(10))逻辑说明errorscoerce参数很关键它把无法解析成数字的非法字符串转成NaN代替直接抛异常适合脏数据多的真实场景。split(、|/)是正则拆分或号逻辑同时处理中文顿号和斜杠两种分隔符这是清洗多值字段时最简单可靠的做法。清洗之后再做分类统计也好、做核密度分析也好误差会小很多。3.4 按行政区划提取特定范围的 POI空间裁剪的正确姿势如果只需要黄浦区或者浦东新区的 POI不必在属性表里筛选所有区县的数据。用空间连接或者空间裁剪的方式更稳妥尤其是当 POI 坐标有微小偏差时属性筛选可能把边界上的点漏掉。在 GeoPandas 中做裁剪常见做法是建立空间索引后再查询import geopandas as gpd # 读取 POI 与行政区划 poi_gdf gpd.read_file(POI_shp/shanghai_poi.shp, encodingutf-8) districts gpd.read_file(District/shanghai_district.shp, encodingutf-8) # 确保两图层坐标系一致常见做法是统一到目标区划的坐标系 districts districts.to_crs(poi_gdf.crs) # 取出浦东新区的外边界 pudong districts[districts[name] 浦东新区] # 空间连接模式裁剪保留落在面内的点 pudong_poi gpd.sjoin(poi_gdf, pudong, howinner, predicatewithin) print(pudong_poi.shape)逻辑说明to_crs是把行政区划图层重新投影到 POI 所在坐标系避免因坐标系不一致产生空间关系错误。sjoin是空间连接predicatewithin表示只保留完全落在面内部的点边界上的点如果因为浮点精度问题被剔除可以改成intersects放宽条件。这个环节是空间分析的常规门槛坐标系统一这一步没做后面的一切统计都不可信。4. 30 米 DEM 数据的正确应用按区裁剪与栅格陷阱4.1 认识 30 米 DEM分辨率和数据格式的边界条件标题里写的 30M 分辨率 DEM指的通常是 30 米分辨率的数字高程模型来源多为航天飞机雷达地形任务或同类公开数据源。30 米代表每个像元对应地面上 30×30 米的面积用来做城市尺度分析够用做地块级高差评估则精度不足。DEM 的常见存储格式是 tif 或 img 栅格这份压缩包里给出的通常是 tif。和矢量数据不同栅格不能像 Excel 一样直接打开看属性需要专门的软件读取ArcGIS 里是加载后查看「图层属性 → 源 → 像元大小」Python 里则是用 rasterio 读取元数据。4.2 ArcMap 中按面图层裁剪 DEM掩码提取与裁剪工具的差别在 ARCGIS 中处理 DEM 时新手最容易搞混的是「按掩膜提取」和「裁剪工具」的边界条件。ARCMAP 里依靠面图层裁剪 DEM 栅格 tif 文件的常用方式是「按掩膜提取」在 ArcToolbox 里路径是 Spatial Analyst 工具 → 提取分析 → 按掩膜提取。输入栅格是 DEM掩膜数据选择行政区划面图层输出就是裁好的局部 DEM。两者差别在于裁剪工具要求输入和输出格式遵循严格的矩形范围掩膜提取则按面要素的几何形状裁剪边缘是渐变的。做地形分析时用按掩膜提取。实际操作中有一个影响结果的因素掩膜面图层和 DEM 的坐标系不一致时裁剪结果可能为空或者边角错位建议在工具参数里先把环境设置中的处理范围改为面边框。4.3 Python 按区批量裁剪 DEMrasterio 加 GeoPandas 组合需要按多个区的边界批量切 DEM 时桌面软件逐个操作效率太低用 rasterio 加 GeoPandas 批量处理是常规做法import geopandas as gpd import rasterio from rasterio.mask import mask # 读取行政区划面图层注意坐标系必须是 DEM 的坐标系 districts gpd.read_file(District/shanghai_district.shp, encodingutf-8) dem_path DEM/shanghai_dem_30m.tif # 读取 DEM 元信息 with rasterio.open(dem_path) as src: dem_crs src.crs districts districts.to_crs(dem_crs) for idx, row in districts.iterrows(): name row[name] geom [row[geometry]] with rasterio.open(dem_path) as src: out_image, out_transform mask(src, geom, cropTrue) out_meta src.meta.copy() # 更新元数据并写入新文件 out_meta.update({ driver: GTiff, height: out_image.shape[1], width: out_image.shape[2], transform: out_transform }) with rasterio.open(fDEM_cut/{name}_dem.tif, w, **out_meta) as dst: dst.write(out_image)逻辑说明mask函数的第二个参数是几何要素列表这里把row[geometry]包成单元素列表传入是因为 rasterio 要求遮罩输入类型为 GeoJSON-like 的几何对象集合。cropTrue表示裁剪后按面元素边界切掉边缘而不是保留矩形。元数据更新是必须步骤因为输出矩阵的尺寸和仿射变换变了不更新写入的 tif 会读到错位的地理范围。处理时如果 DEM 文件较大建议逐个区写完后检查输出文件的像元尺寸是否一致防止因重采样参数缺失导致像元大小漂移。5. 避坑盘点五个高频翻车现场与处理方案5.1 乱码属性表中文全部显示为问号现象在 ArcGIS 中打开 shp 属性表中文字段显示为「??????」或者一堆无法辨认的符号。原因shp 的 .dbf 属性表没有附带编码声明或者 .cpg 文件丢失软件默认按本地编码解析中文就阵亡了。解决用 GeoPandas 读取时指定encodinggbk或encodingutf-8试一遍如果在 QGIS 中打开在图层属性里重新选择编码并保存。读取 shp 后如果中文字段名乱码先把 GeoPandas 读出来的 DataFrame 用to_file重新导出一次ArcGIS 能正常显示。5.2 坐标偏移POI 点整体落入海里或错位到邻近城市现象叠加行政区划图层后POI 点位整体偏移导航到长江口或者杭州湾方向和区划边界对不上。原因POI 图层用的是 WGS84 经纬度坐标但行政区划图层用的是 GCJ02火星坐标两者不加转换直接叠加必然偏移。解决先确认两个图层的crs属性如果坐标系不一致统一转换到同一标准。这里就是所谓的玄学场景坐标系问题不解决所有空间分析结果都是不准的。一般我会在项目开始时先做一次坐标普查花 10 分钟可以省下后面几天的排查时间。5.3 字段缺失Excel 里能看到的列shp 里没有现象同一份 POI 数据Excel 格式里有电话、营业时间这些字段shp 格式的属性表里却只有名称和类别。原因shp 格式的 dBase 字段数量限制在某些场景下会触发字段被截断或者原始数据制作时 shp 本身就只保留核心字段。解决如果分析中必须用完整字段以 Excel 格式为主表shp 的POI_ID和外键做表关联。这个步骤在 Pandas 里用merge操作完成多走一步但数据完整性有保障。5.4 Excel 打开 POI 表导致软件卡死现象Excel 格式的 POI 文件动辄几十万行双击打开后直接无响应或者往下滚动就卡成白屏。原因Excel 本身的行数限制和渲染性能瓶颈POI 这种大规模数据量放到数据库或专业数据分析工具里更合适。解决数据量大的时候用 Python 的 Pandas 处理或者用 SQLite 把 Excel 导入成数据库表。开源 EXCEL 数据库软件或数据仓库方案在这个场景下比 Excel 本身高效得多。如果只是给别人快速浏览先用 Pandas 抽样生成一个预览版 Excel。5.5 解压后文件大小不对或图层加载提示缺少数据现象解压后 POI_shp 目录下只有一个.shp主文件.dbf和.shx丢失或者加载图层时弹出「数据源不可读」。原因7z 解压时磁盘空间不足、中断或者原始压缩包在传输过程中缺失文件成员。解决重新解压前先检查磁盘剩余空间解压完成后核对目录文件数。shp 加载失败时先检查同目录是否同时存在.shp/.shx/.dbf/.prj四件套。从那次之后我每次解压完都先跑一遍文件清单统计确认记录数和压缩包说明一致再进入下一步。6. 进阶玩法把 Excel 格式 POI 批量入库与 shp 转 3DTiles当 POI 数据量大到影响读写效率或者需要支撑 Web 端地图应用的动态查询时把 Excel 格式 POI 导入数据库是必经的一段路。这里我用 SQLite 做演示逻辑通用换成 PostgreSQL 或者 MySQL 只是改连接字符串的事。操作分两步第一步在 Python 里把 Excel 读取为 DataFrame第二步通过to_sql写入数据库表。注意写入前把字段类型设置到位尤其是经纬度需要明确指定为 REAL 类型否则后续做范围查询时会被存储成文本导致排序错乱import pandas as pd import sqlite3 poi_df pd.read_excel(POI_excel/shanghai_poi_2020.xlsx, dtype{POI_ID: str}) conn sqlite3.connect(shanghai_poi.db) poi_df.to_sql(poi, conn, if_existsreplace, indexFalse) cur conn.cursor() cur.execute(CREATE INDEX idx_poi_lat ON poi(纬度)) cur.execute(CREATE INDEX idx_poi_lng ON poi(经度)) conn.commit() # 验证写入结果 count cur.execute(SELECT COUNT(*) FROM poi).fetchone()[0] print(f写入记录数: {count})逻辑说明to_sql的if_existsreplace表示如果表已存在则替换重建适合反复实验的场景但生产环境请改成append或者先DROP TABLE再写入。索引的创建位置放在写入之后数据量大的时候建索引会稍慢但对后续按经纬度范围查询的性能提升显著。验证记录数是常规习惯号码对不上说明 Excel 读取阶段就有问题不需要再往下查。如果目标是做三维可视化shp 转 3DTiles 是大场景渲染的首选方案。把 POI 提取成点要素并赋予高度属性后用工具转换即可。这套流程里这份资源的价值从二维叠加分析延伸到了三维场景展示DEM 正好可以作为高度场数据一起参与构建。我自己的习惯是先把 POI 按类别拆分几组测试转换避免一次大规模转换失败还排查不了。从那以后我每次拿到新数据都会强制走一遍这个顺序核查坐标系、核查编码、确认字段完整度、再做正经分析。这套血泪经验换来的工作流希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站