2026/10/3 10:16:28

上海2020年POI矢量数据集处理全攻略:从7z解压到坐标对齐与空间分析

上海2020年POI矢量数据集处理全攻略:从7z解压到坐标对齐与空间分析 简介这份资源是面向GIS从业者、城市规划研究者与地图开发者的上海市2020年POI矢量数据集整合了兴趣点、数字高程模型与行政区划三类核心地理信息可用于地形分析、商业选址、交通规划及社会服务分布评估等场景。压缩包共126个文件约80.65MB以shp、dbf、shx、prj等Shapefile配套文件为主便于在ArcGIS、QGIS等平台直接加载与空间分析同时提供14个xlsx表格方便非GIS用户查看和统计POI属性另含tif、tfw、ovr等栅格文件支撑30米分辨率DEM的地形建模。数据覆盖医疗保健、住宿、商务住宅、公共设施、风景名胜、科教文化、生活服务、公司企业等多个类别兼顾空间分析与表格统计两种使用习惯。目前已有815人学习下载适合需要上海地区基础地理数据开展研究或项目实践的用户参考使用。1. 上海2020年POI矢量数据集从30米DEM到shp与Excel的完整拆解如果你正在做上海城市研究、商业选址、可达性分析或者城市计算大概率绕不开一套基础底图数据2020年的上海POI矢量数据外加30米分辨率DEM、行政区划边界以及shp和Excel两种格式的POI。这套数据在圈子里被反复转手文件名通常就是那个熟悉的.7z压缩包。它解决的核心问题是让你不用从高德或百度一条条爬就能拿到一份相对完整的、带坐标、带分类、能直接进ArcGIS或QGIS的上海兴趣点底表。适合谁做城市GIS分析的研究生、做门店选址的数据分析师、做城市数字孪生的工程师以及需要一份标准行政区划边界来裁剪数据的任何人。但拿到压缩包只是第一步真正让人翻车的是解压、坐标系、字段乱码和DEM与POI的对齐。这篇就按我实际处理这套数据的顺序把每一步讲透。2. 解压与数据体检7z、shp、Excel三件套先过一遍2.1 Linux和Windows下解压7z的正确姿势.7z这个格式在Windows上双击就能开但在Linux服务器上很多人第一反应是unzip然后报错。7z不是zip得用p7zip。我一般先确认装没装# Debian/Ubuntu系 sudo apt-get install p7zip-full # CentOS/RHEL系 sudo yum install p7zip p7zip-plugins # 解压到当前目录保留目录结构 7z x 上海市2020年POI矢量数据集.7z -o./shanghai_poi_2020 # 只看压缩包内容不解压先体检 7z l 上海市2020年POI矢量数据集.7z7z x里的x是保留完整路径解压-o指定输出目录注意-o和路径之间没有空格。先7z l列一遍内容很重要因为这类数据集经常嵌套多层比如POI/shp/和POI/excel/分开DEM单独一个文件夹。提前看清结构能避免解压完在一堆中文目录里迷路。提示如果7z提示密码正确但一直报错九成是压缩包在传输过程中损坏或者文件名编码问题。先7z t做完整性测试再考虑重新获取。2.2 用Python给shp和Excel做一次字段体检解压完别急着往ArcGIS里拖。先写个脚本把shp的坐标系、字段、记录数以及Excel的sheet和列名扫一遍。这一步能提前发现坐标系是WGS84还是GCJ02、字段有没有乱码、POI分类字段叫什么。import geopandas as gpd import pandas as pd import os base ./shanghai_poi_2020 # 1. 体检shp坐标系、字段、记录数 shp_path os.path.join(base, POI_shp, shanghai_poi.shp) gdf gpd.read_file(shp_path) print(坐标系:, gdf.crs) print(字段:, list(gdf.columns)) print(记录数:, len(gdf)) print(几何类型:, gdf.geom_type.unique()) print(gdf.head(3)) # 2. 体检Excelsheet名、列名、行数 xlsx_path os.path.join(base, POI_excel, shanghai_poi.xlsx) xls pd.ExcelFile(xlsx_path) print(Sheet列表:, xls.sheet_names) df pd.read_excel(xlsx_path, sheet_namexls.sheet_names[0]) print(列名:, list(df.columns)) print(行数:, len(df)) print(df.head(3))这段代码的关键输出是gdf.crs。如果显示EPSG:4326那是经纬度WGS84如果显示EPSG:4490那是CGCS2000如果显示None说明坐标系丢了后面做空间分析会全错。字段方面POI数据常见的列有name、type、address、lng、lat但不同来源命名差异很大有的叫大类/中类/小类有的叫category。Excel和shp的字段最好对一遍确认是不是同一批数据两种格式。2.3 行政区划边界和30米DEM的快速核验行政区划shp通常是一个面文件用来裁剪POI或做分区统计。DEM一般是GeoTIFF30米分辨率意味着每个像素代表地面30米×30米。核验DEM最直接的方法是看它的范围是否覆盖上海全域以及像素值范围是否合理。import rasterio # 行政区划边界 admin gpd.read_file(os.path.join(base, boundary, shanghai_districts.shp)) print(区县数量:, len(admin)) print(边界坐标系:, admin.crs) print(边界范围:, admin.total_bounds) # 30米DEM dem_path os.path.join(base, DEM, shanghai_dem_30m.tif) with rasterio.open(dem_path) as src: print(DEM坐标系:, src.crs) print(DEM尺寸:, src.width, x, src.height) print(分辨率:, src.res) print(范围:, src.bounds) dem src.read(1) print(高程范围:, dem.min(), -, dem.max())src.res应该接近(30, 30)或者(0.000277, 0.000277)度为单位。如果分辨率是0.000277度换算到赤道附近约30米上海纬度下实际约25米左右这是正常的。DEM高程范围上海一般在0到100米之间如果出现负几百或几千说明NoData值没处理通常是-9999或-32768。3. 坐标系对齐POI、DEM、行政区划三者必须统一3.1 为什么你的POI会偏移几百米这是血泪经验里最常见的一条POI是从高德或百度爬的坐标系是GCJ02或BD09而行政区划和DEM是WGS84。直接叠在一起POI会整体偏移几百米在市区可能偏到隔壁街道。判断方法很简单拿一个已知地标比如人民广场看POI落在哪。如果明显偏了就得做坐标转换。GCJ02转WGS84没有官方公式常用的是开源的coord-convert或eviltransform算法。我一般用pyproj配合已知的转换参数或者直接用coord-convert库。from coord_convert.transform import gcj2wgs import pandas as pd df pd.read_excel(xlsx_path) # 假设列名是lng, lat且是GCJ02 df[lng_wgs], df[lat_wgs] zip(*df.apply( lambda r: gcj2wgs(r[lng], r[lat]), axis1 )) # 转成GeoDataFrame from shapely.geometry import Point gdf_poi gpd.GeoDataFrame( df, geometry[Point(x, y) for x, y in zip(df[lng_wgs], df[lat_wgs])], crsEPSG:4326 ) gdf_poi.to_file(shanghai_poi_wgs84.shp, encodingutf-8)gcj2wgs返回的是WGS84经纬度。转换后一定要再叠一次行政区划验证确保POI落在正确的区县内。如果偏移依然存在检查是不是BD09BD09转GCJ02再转WGS84是两步。3.2 把DEM和行政区划统一到同一投影做坡度、地形起伏度分析时经纬度坐标系算出来的距离是度不是米必须投影。上海常用的是UTM 51NEPSG:32651或者CGCS2000 3度带。我一般统一到EPSG:32651因为UTM在上海市范围内变形小计算方便。# 行政区划投影 admin_utm admin.to_crs(EPSG:32651) admin_utm.to_file(shanghai_districts_utm.shp, encodingutf-8) # DEM投影用rasterio的warp from rasterio.warp import calculate_default_transform, reproject, Resampling dst_crs EPSG:32651 with rasterio.open(dem_path) as src: transform, width, height calculate_default_transform( src.crs, dst_crs, src.width, src.height, *src.bounds ) kwargs src.meta.copy() kwargs.update({ crs: dst_crs, transform: transform, width: width, height: height }) with rasterio.open(shanghai_dem_utm.tif, w, **kwargs) as dst: reproject( sourcerasterio.band(src, 1), destinationrasterio.band(dst, 1), src_transformsrc.transform, src_crssrc.crs, dst_transformtransform, dst_crsdst_crs, resamplingResampling.bilinear )Resampling.bilinear适合连续型DEM如果是土地利用分类栅格要用Resampling.nearest保持类别值不变。投影后DEM分辨率会从度变成米大约30米左右具体看纬度。3.3 用行政区划裁剪POI和DEM的实操裁剪是分区统计的前提。POI用clipDEM用mask。注意裁剪前两者坐标系必须一致。# 裁剪POI到上海边界 poi_utm gdf_poi.to_crs(EPSG:32651) poi_clip gpd.clip(poi_utm, admin_utm) poi_clip.to_file(shanghai_poi_clip.shp, encodingutf-8) # 裁剪DEM到上海边界 from rasterio.mask import mask import json with rasterio.open(shanghai_dem_utm.tif) as src: geoms [json.loads(admin_utm.to_json())[features][0][geometry]] # 如果行政区划是多个面需要合并 admin_union admin_utm.unary_union geoms [admin_union.__geo_interface__] out_image, out_transform mask(src, geoms, cropTrue) out_meta src.meta.copy() out_meta.update({ height: out_image.shape[1], width: out_image.shape[2], transform: out_transform }) with rasterio.open(shanghai_dem_clip.tif, w, **out_meta) as dst: dst.write(out_image)unary_union把多个区县合并成一个整体避免裁剪时出现区县之间的缝隙。裁剪后DEM的NoData区域会变成0或指定值后续统计时要排除。4. 避坑与排查POI数据集处理中最容易翻车的5个点4.1 现象Excel打开shp属性表全是乱码原因shp的.dbf文件默认编码是GBK或Latin1而Python或QGIS按UTF-8读。解决读的时候指定encodinggbk或者用geopandas的read_file(..., encodinggbk)。如果还是乱码用shapechk工具修复dbf头文件或者用ogr2ogr转一次编码ogr2ogr -f ESRI Shapefile output.shp input.shp -lco ENCODINGUTF-84.2 现象7z解压到一半报“数据错误”原因压缩包下载不完整或传输损坏。解决先7z t测试如果报错重新获取。如果确认文件完整但Linux下文件名乱码加-mcp936指定GBK代码页7z x -mcp936 上海市2020年POI矢量数据集.7z4.3 现象POI数量对不上shp比Excel少几千条原因shp字段名有长度限制10个字符导出时字段被截断或记录丢失或者Excel里有重复行shp去重了。解决以Excel为准重新导出shp导出前把字段名改成英文短名比如name、type、lng、lat。4.4 现象DEM和POI叠在一起POI全跑到山里原因DEM的坐标系是投影坐标POI是地理坐标ArcGIS自动投影但QGIS可能不自动。解决统一到同一坐标系再叠加。在QGIS里用“重新投影图层”工具把两者都转到EPSG:32651。4.5 现象行政区划边界和POI对不上POI落在边界外原因行政区划是2020年之前的旧边界或者POI本身有偏移。解决先做坐标转换验证再用spatial join检查有多少POI落在边界外。如果少量落在边界外可能是边界简化导致用buffer(100)容差处理。5. 从POI到分析分类统计、核密度与DEM叠加的进阶技巧拿到清洗好的数据后真正有价值的是分析。我一般先做POI分类统计按区县汇总各类POI数量再和DEM做叠加看商业设施是否集中在低海拔区域。这里给一个完整的核密度估计加DEM采样的例子。import numpy as np from scipy.stats import gaussian_kde import matplotlib.pyplot as plt # 1. 按区县统计POI数量 poi_clip[district] poi_clip[geometry].apply( lambda p: admin_utm[admin_utm.contains(p)][name].values[0] if any(admin_utm.contains(p)) else 未知 ) count_by_district poi_clip.groupby(district).size() print(count_by_district.sort_values(ascendingFalse)) # 2. 核密度估计取餐饮类POI food poi_clip[poi_clip[type].str.contains(餐饮, naFalse)] coords np.vstack([food.geometry.x, food.geometry.y]) kde gaussian_kde(coords, bw_method0.05) # 生成网格 xmin, ymin, xmax, ymax admin_utm.total_bounds xx, yy np.mgrid[xmin:xmax:500j, ymin:ymax:500j] positions np.vstack([xx.ravel(), yy.ravel()]) zz kde(positions).reshape(xx.shape) # 3. 采样DEM高程 with rasterio.open(shanghai_dem_clip.tif) as src: elev src.read(1, out_shape(500, 500)) elev np.where(elev -100, np.nan, elev) # 4. 叠加可视化 fig, ax plt.subplots(1, 2, figsize(14, 6)) ax[0].imshow(zz, extent[xmin, xmax, ymin, ymax], originlower, cmaphot) ax[0].set_title(餐饮POI核密度) ax[1].imshow(elev, extent[xmin, xmax, ymin, ymax], originlower, cmapterrain) ax[1].set_title(30米DEM高程) plt.show()bw_method0.05控制核密度平滑程度值越小越尖锐值越大越平滑。500j表示生成500×500网格网格越密计算越慢。DEM采样时用out_shape重采样到同样网格方便逐像素对比。如果发现餐饮POI核密度高值区和DEM低海拔区高度重合说明商业设施确实集中在平原这是符合直觉的但如果你做的是山区城市结论可能相反。最后一个习惯每次处理完这套数据我都会把坐标系、字段映射、裁剪范围写进一个README.md和输出文件放一起。因为三个月后你绝对记不住当时用的是GCJ02还是WGS84也记不住为什么某个区少了200条POI。这个习惯帮我省了无数次返工。希望帮到你。本文还有配套的精品资源点击获取