尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

杭州市POI数据集处理实战:从7z解压到GIS分析

杭州市POI数据集处理实战:从7z解压到GIS分析 简介杭州市2020年POI数据集是一份面向GIS开发、城市规划与数据分析人员的空间数据资源包含30米分辨率DEM、行政区划边界以及覆盖生活服务、餐饮、购物、住宿、风景名胜等多类业态的兴趣点数据可直接用于空间分析、地图制图或选址研究。整个压缩包共120个文件以shp及配套的dbf、prj、shx等矢量文件为主另有13个xlsx表格和部分tif高程数据包体约49.62MB结构清晰便于分层使用。已有868人学习下载适合需要快速获取杭州市基础地理数据做实验或项目验证的读者。数据同时提供shp和excel两种格式兼顾GIS软件与办公场景DEM与行政区划可辅助地块解读与三维展示POI分类较细能支撑可达性分析、商圈识别等进阶应用。数据标注为非涉密使用门槛低可作为日常研究与教学练习的可靠底图。1. 拿到一个市域级 POI 数据集先别急着打开 ArcGIS做城市数据分析和 GIS 开发的读者拿到「杭州市 2020 年 POI 数据集包含 30M 分辨率 DEM、行政区划、shp 格式 POI、excel 格式 POI 数据.7z」这个压缩包时第一反应往往是直接双击解压把 shp 拖进地图里看。但这类数据集有一个共性文件完整不代表数据可用坐标系、编码、字段语义才是真正的门槛。这篇文章会把这份数据集拆成四块来讲——POI 的两种格式、DEM 与行政区划的用途、7z 压缩的处理方式以及从解压到出图的全流程操作。适合需要把外部 GIS 数据接进自己项目的工程师也适合做城市分析但被数据格式卡住的新手。2. POI 数据集里的格式选型shp 和 excel 各自承担什么2.1 先搞清楚 POI 在 GIS 语境里的含义POI全称 Point of Interest即兴趣点。它代表地图上一个具体的、有业务意义的点比如餐饮门店、加油站、学校、医院。和路网、建筑物轮廓这类线面数据不同POI 的核心是「点在哪儿 这个点是什么」。注意这里的 POI 和 Java 生态里的 Apache POI API 没有任何关系——那个是操作 Office 文档的库经常被拿来读写 Excel热搜里提到的apache poi 4.1.0 xssfexporttoxml xxe漏洞属于办公文档解析领域和本数据集完全不沾边。一个市域级的 POI 数据集通常包含几十万到上百万条记录。杭州作为大城市2020 年的 POI 数量至少在几十万量级。这样的数据量用 shp 格式存储是合适的因为 shapefile 本身就是为矢量点数据设计的存储格式。2.2 shp 格式GIS 分析的主战场shapefile 虽然叫「一个」文件实际落地是多个文件的集合至少包含.shp几何、.shx索引、.dbf属性表还可能附带.prj坐标系、.cpg字符编码。这种多文件结构是新手最容易踩坑的地方——只拷贝.shp一个文件到别处打开就会报错。用geopandas读取这种 POI 数据是常见做法下面这段代码能在不打开桌面软件的情况下快速了解数据结构import geopandas as gpd # 读取杭州市 POI 的 shp 文件注意路径里的中文编码问题 poi gpd.read_file(杭州市2020年POI数据/hangzhou_poi.shp, encodingutf-8) print(poi.shape) # (行数, 列数) print(poi.columns) # 字段名列表 print(poi.crs) # 坐标系信息 print(poi.head()) # 前5行读取时encoding参数经常要试有的数据源是utf-8有的是gbk。试错的方法很简单——读出来看中文字段名是否乱码乱码就换编码。.dbf文件对字段名长度有限制超过 10 个字符会被截断所以字段名往往是简写需要通过字段注释或数据字典来还原语义。2.3 excel 格式给业务人员用的接口同一个 POI 数据集为什么要再提供一份 excel 格式因为不是所有协作方都会用 GIS 工具。业务部门、运营团队用 Excel 打开.xlsx直接筛选、做透视表比让他们装 QGIS 现实得多。但这个字段通常在 shp 里是否完整一致需要验证。常见的做法是读两个文件做行数和 ID 的交叉核对import pandas as pd poi_excel pd.read_excel(杭州市2020年POI数据/hangzhou_poi.xlsx) poi_shp gpd.read_file(杭州市2020年POI数据/hangzhou_poi.shp, encodingutf-8) # 比较 ID 唯一性判断两份数据是否能互相印证 print(poi_excel[poi_id].is_unique) print(poi_shp[poi_id].is_unique) print(set(poi_excel[poi_id]) set(poi_shp[poi_id]))Excel 格式的固有问题是经纬度列被当作文本存储或者小数位被截断。检查办法是看数据类型dtype如果是object而不是float64就需要用pd.to_numeric做转换。另外 Excel 另一个常见坑是行列数超过 1048576 行时的截断风险——市域 POI 数据通常不至于到这个量级但如果是全国数据就要留意。2.4 DEM 与行政区划在数据集里的角色DEMDigital Elevation Model是数字高程模型30M 分辨率意味着每个像元代表地面 30 米 × 30 米的区域。这个精度在城市级别恰好够用能做坡度、坡向分析能判断 POI 所在位置的地形起伏也能用来做可视域分析。30M 相比ALOS 12.5米那种精细数据要粗一些但城市地形相对平缓做宏观分析时差别不大。行政区划数据在本数据集里是边界约束。做 POI 统计时把点叠到行政区面里按区县聚合这是最常见的用法。用空间连接实现import geopandas as gpd district gpd.read_file(杭州市2020年POI数据/hangzhou_district.shp, encodingutf-8) poi gpd.read_file(杭州市2020年POI数据/hangzhou_poi.shp, encodingutf-8) # 空间连接把每个 POI 归属到所在行政区 join gpd.sjoin(poi, district, howleft, opwithin) # 按区县统计 POI 数量 count_by_district join.groupby(district_name).size().reset_index(namepoi_count) print(count_by_district.sort_values(poi_count, ascendingFalse))sjoin的opwithin是点面连接最常用的空间谓词表示点必须在面内部。边界上的点如果出现未匹配情况通常是坐标系不一致导致的这在第 3 章统一坐标系后会解决。3. 7z 压缩包的解压与数据落地从命令行到 Python3.1 用 7z 命令行核对压缩包完整性.7z格式的压缩率比 zip 高一个包含 shp 多文件 tif 栅格 xlsx 的数据集压成 7z 能省不少空间。但 7z 在部分系统上不是默认支持格式所以拿到压缩包第一步是确认工具可用。Windows 上安装 7-Zip 后命令行工具是7z.exeLinux 上通常需要自己安装p7zip或7zip包。先不要急着解压先列出压缩包内容7z l 杭州市2020年POI数据集.7zl参数是 list 的缩写只列出内容不解压。这一步能看到压缩包内是否有分卷、目录结构是否符合预期。一个 7z 文件内部可能包含多个文件确认文件结构后再执行解压7z x 杭州市2020年POI数据集.7z -o./data -p参数说明x表示解压并保留目录结构-o指定输出目录注意-o后面没有空格-p后接密码如果压缩包没加密就直接省略。部分数据源会加密压缩包密码通常写在下载说明里7z x会在没有密码时交互式提示输入。解压完成后检查文件数量是否和l列出的一致尤其注意.shp的同名伴随文件.shx、.dbf、.prj、.cpg是否齐全。缺.prj文件是最麻烦的意味着坐标系信息丢失后面要用坐标值反推。3.2 Python 侧处理 7z 文件如果整个工作流都在 Python 里不想为解压切到命令行可以用py7zr库。它在 Linux、Windows、macOS 上都能用接口也很简洁import py7zr # 打开压缩包并解压到指定目录 with py7zr.SevenZipFile(杭州市2020年POI数据集.7z, moder) as archive: archive.extractall(path./data) # 打印压缩包内文件列表 print(archive.getnames())getnames()返回的是压缩包内部所有文件路径的列表可以在解压前先打印出来看结构。如果文件很多可以先只解压需要的后缀比如只提取.shp相关文件再按需解压 DEM 的.tif。但我不建议这样分次解压——shp 和 dbf 是配套的少一个都打不开。3.3 统一坐标系把 POI 和 DEM 摆到同一张桌上解压完成后最关键的检查是坐标系。POI 数据最常见的坐标系设置是 WGS84EPSG:4326或 GCJ02火星坐标系而 DEM 栅格一般用投影坐标系比如 UTM 或高斯-克吕格。杭州区域常用的投影带是 UTM 50N 或 CGCS2000 3 度带。先分别查看四个数据源的坐标系import geopandas as gpd import rasterio poi gpd.read_file(data/hangzhou_poi.shp, encodingutf-8) district gpd.read_file(data/hangzhou_district.shp, encodingutf-8) # 查看矢量数据的坐标系 print(POI CRS:, poi.crs) print(District CRS:, district.crs) # 查看 DEM 栅格信息 with rasterio.open(data/dem30m.tif) as dem: print(DEM CRS:, dem.crs) print(DEM bounds:, dem.bounds) print(DEM resolution:, dem.res) print(DEM nodata:, dem.nodata)rasterio.res输出的是像元尺寸如果显示(30.0, 30.0)或类似数值说明 DEM 保持原始分辨率。但如果打印结果是(0.0002777778, 0.0002777778)这种度数单位说明这个 DEM 被重投影到了地理坐标系下这时要谨慎做坡度计算。如果 POI 和行政区划坐标系不一致用to_crs统一# 假设行政区划是投影坐标系把 POI 转过去 poi_projected poi.to_crs(district.crs)选择以行政区划的坐标系为基准是因为后续空间连接大多以面为容器保持面的坐标系不变做基础。如果 DEM 需要与矢量叠加用rasterio.reproject重采样到统一 CRS重采样方法推荐Resampling.bilinear。3.4 数据质量初检空几何、重复点、越界点坐标系统一后再做一轮质量检查。常见问题包括空几何geometry 为 None、重复经纬度的点、明显超出杭州市范围的坐标。这类问题在数据生产阶段几乎是必然存在的下面这段脚本能一次性定位问题点import geopandas as gpd import numpy as np poi gpd.read_file(data/hangzhou_poi.shp, encodingutf-8) # 1. 空几何检查 print(空几何数量:, poi.geometry.isna().sum()) # 2. 重复点检查:基于经纬度列去重 poi[lon_lat] poi[lon].astype(str) _ poi[lat].astype(str) dup_mask poi[lon_lat].duplicated(keepFalse) print(重复点数量:, dup_mask.sum()) # 3. 边界范围检查:杭州大致在经度118.3~121.0,纬度29.0~30.8之间 bounds_mask ( (poi[lon] 121.5) | (poi[lon] 118.0) | (poi[lat] 30.9) | (poi[lat] 29.0) ) print(疑似越界点数量:, bounds_mask.sum()) print(poi.loc[bounds_mask, [poi_name, lon, lat]].head(10))越界点的处理策略取决于用途如果做全量统计建议过滤掉如果做空间分布展示可以保留并检查是否是飞地数据比如杭州在某个区域有实际管辖的飞地。 以及还有坐标在市区范围但被错误标记了经纬度的情况比如经纬度互换、小数点错位这类错误靠范围过滤查不出来需要抽检人工确认。4. 用 DEM 和 POI 做组合分析从聚合统计到坡度计算4.1 按行政区划做 POI 密度统计把 POI 数据落到行政区划上做统计是城市分析里最常用的操作。第 2 章的sjoin只能给出数量实际项目里往往要计算密度——POI 数量除以行政区面积。因为杭州市各区面积差异很大靠绝对数量比较强弱会失真。密度计算的单位一般是「个/平方公里」面积需要先将面数据投影到等面积坐标系import geopandas as gpd district gpd.read_file(data/hangzhou_district.shp, encodingutf-8) poi gpd.read_file(data/hangzhou_poi.shp, encodingutf-8) # 投影到适合面积计算的等积投影:Albers 等积投影适合中国中部 district_proj district.to_crs(EPSG:9822) district_proj[area_km2] district_proj.geometry.area / 1e6 # POI 也投影到相同坐标系再做空间连接 poi_proj poi.to_crs(EPSG:9822) join gpd.sjoin(poi_proj, district_proj, howleft, opwithin) density ( join.groupby(district_name) .size() .reset_index(namepoi_count) ) density density.merge( district_proj[[district_name, area_km2]], ondistrict_name, howleft ) density[poi_density] density[poi_count] / density[area_km2] print(density.sort_values(poi_density, ascendingFalse).head(10))这段代码里有两个关键点。第一使用EPSG:9822等积投影确保面积计算不因投影变形产生较大误差南北跨度大的城市尤其明显。第二groupby之后重新 merge 面积列因为聚合操作会丢掉非分组字段。 这里有一个容易忽略的边界问题杭州西湖区与西湖水面重叠的区域属于西湖风景区管理处管辖边界归属和实际管理方不同。如果分析目的是商业选址这种边界语义差异需要考虑必要时用缓冲区分析做补充。4.2 30M DEM 的坡度计算与坡向提取POI 数据是点DEM 是连续表面两者结合最常见的场景是分析地物所在位置的坡度。比如判断全杭州的餐饮 POI 是否大多分布在缓坡区域这是个有意思的统计题。坡度计算可以直接用gdaldem命令行工具# slope 计算,结果以度为单位输出 gdaldem slope data/dem30m.tif data/slope.tif -s 1.0 -p # hillshade 山体阴影,用于可视化 gdaldem hillshade data/dem30m.tif data/hillshade.tif -z 2.0 -az 315.0 -alt 45.0参数说明-s是垂直比尺因子单位与水平方向相同时设为 1.0一般 30M 数据不用改-p表示输出坡度的单位为度percent 不用此参数-z是高度夸大系数可视化时我更常用 1.0真实展示地形效果时可以放大-az是光源方位角0-360315 度是地图学上的默认西北光照-alt是光源高度角45 度适中。如果项目代码在 Python 环境中不希望调用外部命令用rasterio也能算需要自己写梯度公式import rasterio import numpy as np from rasterio.transform import Affine with rasterio.open(data/dem30m.tif) as src: dem src.read(1).astype(float64) transform src.transform nodata src.nodata # 将 nodata 置为 NaN 防止参与梯度计算 dem[dem nodata] np.nan # 计算 x, y 方向的梯度 dx, dy np.gradient(dem) slope_rad np.arctan(np.sqrt(dx**2 dy**2)) slope_deg np.degrees(slope_rad) # 输出统计信息 print(坡度最大值:, np.nanmax(slope_deg)) print(坡度平均值:, np.nanmean(slope_deg))这里的np.gradient用的是中心差分对 30M 分辨率的 DEM 足够。注意np.gradient计算时按照行列间距为 1 像素来计算如果要做物理单位的精确计算需要传入transform.ax 方向像元大小作为间距参数。上面代码简化了这一点在大多数城市宏观分析中影响不大。真正影响大的反而是填洼——原始 DEM 里可能有错误的负值凹坑做水文分析之前必须用gdaldem filldepressions处理。4.3 提取 POI 所在位置的高程与坡度值把 DEM 的连续值提取到 POI 点上是点栅格叠加的典型操作。比如分析商圈 POI 的海拔分布或者做洪涝风险评估时重点判断低洼处 POI 的密度。提取做法是rasterio.sampleimport geopandas as gpd import rasterio poi gpd.read_file(data/hangzhou_poi.shp, encodingutf-8) # 确保 POI 坐标与 DEM 的坐标系一致 dem_crs EPSG:4326 poi_wgs84 poi.to_crs(dem_crs) # 获取经纬度坐标对 coords [(x, y) for x, y in zip(poi_wgs84.geometry.x, poi_wgs84.geometry.y)] with rasterio.open(data/dem30m.tif) as dem: # sample 返回生成器,逐个提取像元值 elevs [val[0] for val in dem.sample(coords)] # 注意 sample 不会自动处理 nodata,需要自己识别 poi_wgs84[elevation] elevs # 把 nodata 值替换为 NaN poi_wgs84[elevation] poi_wgs84[elevation].replace(dem.nodata, np.nan) print(poi_wgs84[[poi_name, elevation]].head(20))这个操作的坑在于sample遇到 nodata 时会直接返回原始值比如 -9999不会自动变成 NaN所以上面手动替换了一次。如果 DEM 的范围没有完全覆盖 POI比如边缘的点落在 DEM 文件边界外sample会返回 nodata 值而不是报错这也是用过滤兜底的原因。通常在业务分析中我们会额外标记poi 是否在 dem 覆盖范围内避免把这些点当成海拔 0 参与统计。5. 验证数据可信度的 3 个硬核技巧坐标系反推、shp 转 txt、压缩包哈希校验拿到外部数据集最容易被坑的是「数据打开没问题但结论一算就跑偏」。最后一章说 3 个我在项目里常用的验证技巧。首先坐标系反推。如果.prj文件缺失你要用坐标值的量级来判断。杭州中心的经纬度大约在经度 120.1、纬度 30.3 附近。打开 shp 的属性表看坐标值如果在这附近大概率是 EPSG:4326经纬度如果看到的是 2100000 附近的大数值如 X: 21300000Y: 3300000那是 CGCS2000 3 度带投影坐标。偶尔还会遇到坐标值在 500000 附近这是 UTM 的横坐标东移后的结果。用坐标值的直觉判断往往比盲目试坐标系更快也更接近问题本质。其次shp 转 txt 导出检查。这里说的 txt 是通用的制表符分隔或逗号分隔文本目的是用文本编辑器直接审查数据内容绕开 GIS 软件的图形界面。用geopandas导出时注意编码import geopandas as gpd poi gpd.read_file(data/hangzhou_poi.shp, encodingutf-8) # 导出为 CSV 文件,注意编码用 utf-8-sig 方便 Windows Excel 打开 poi_text poi.drop(columns[geometry]) # 去掉几何列,纯文本内容 poi_text.to_csv(poi_check.csv, indexFalse, encodingutf-8-sig)导出后用 Excel 或wc -l检查行数和文本内容。这一步能发现 GIS 工具里看不见的问题比如字段值里夹杂了不可见字符、制表符导致列错位、简介字段里带换行符等。这些在属性表里显示正常但导出到外部系统时会导致解析失败。最后压缩包哈希校验。数据源提供方有时会在下载页同时给出 SHA-256 或 MD5 校验值。7z 文件在传输中可能损坏损坏后的表现通常是解压到一半报「数据错误」但也有个别情况是解压成功但内部某个 shp 文件已损坏。稳妥的做法是下载后先做哈希比对# Linux 下计算 sha256 sha256sum 杭州市2020年POI数据集.7z # Windows PowerShell 下计算哈希 Get-FileHash -Algorithm SHA256 杭州市2020年POI数据集.7z两条命令都会输出一个 64 位的十六进制字符串与下载页标注的哈希值逐字符比对。注意 7z 文件在压缩时如果用到了分卷文件名如.7z.001哈希校验要基于分卷合并后的完整文件单独校验每个分卷没有意义。如果数据源没有提供哈希值至少解压后对内部文件跑一次ogrinfo验证ogrinfo -so data/hangzhou_poi.shp hangzhou_poi输出中的Feature Count如果是个合理的整数并且能正常列出字段列表说明这个 shp 没有结构性损坏。把这一系列校验脚本固化成一个小工具集以后再拿到类似的 POI 数据集或 DEM 数据先跑一遍再谈分析能省下大量排错时间。本文还有配套的精品资源点击获取
返回列表