
简介这份上海市2020年POI矢量数据集整合全市兴趣点、30米分辨率DEM与行政区划边界面向GIS分析师、城市规划师及地图开发者可用于地形模拟、商业选址和公共服务评估。数据同时提供Shapefile和Excel两种格式前者含shp/dbf/prj等组件适合ArcGIS、QGIS空间分析与编辑后者为xlsx表格便于业务人员直接做统计筛选。压缩包共126个文件除上述格式外还包括tif高程栅格及配套文件整体约80.65MB。目前已有815人学习下载。借助区县边界、POI分类与DEM可快速开展人口分布对照、设施可达性、坡度日照等城市空间量化分析双格式设计兼顾了专业制图与日常办公需求是理解2020年上海城市格局的实用数据基础。1. 拿到这个7z包先别急着解压上海2020年POI数据集里到底有什么做GIS和空间数据分析的人一定经历过为凑一套完整基础数据在各论坛和网盘之间来回折腾的日子。这个标题里出现的上海市2020年POI矢量数据集不只是一堆点它是把三样东西打包在了一起带空间位置的shp格式POI、方便按属性筛选和二次编辑的excel格式POI外加一张30米分辨率的DEM高程栅格和行政区划边界。换句话说拿到这个包你既能画设施分布也能算地形起伏还能按行政区做裁剪统计。它适合规划院做现状调研、商业选址看周边配套、高校做课程设计也适合刚转行做空间数据分析的人拿来做入门练手。在解压之前先把包里可能是什么、怎么拆、拆完先检查什么这两件事弄清楚能帮你省下后面一大半的返工时间。2. 拆包与盘货7z解压、目录结构与字段的第一次摸底2.1 为什么是7z而不是zip高压缩率与解压口令全量POI动辄几十万条记录属性表里还有类别、名称、地址、电话等长文本字段原始shp和excel合起来很容易超过1GB。用7z压主要看中两点一是压缩率高同一份POI数据用7z压完通常比zip再小20%到30%适合网盘传输二是它支持分卷和加密如果发布者做了分卷你得把所有分卷放在同一目录下再解压。在Linux服务器上解压时我一般用p7zip提供的7z命令。核心命令是7z x 上海市2020年POI矢量数据集.7z -o./shanghai_poi_2020 -yx表示解压并保留目录结构-o指定输出目录注意-o后面不要加空格这是7z一贯容易踩的坑。-y是在遇到覆盖询问时自动同意批量解压省得盯着终端。如果压缩包设置了密码追加-p密码不想让密码出现在终端历史里就只写-p回车后交互输入。解压完成后用7z l查看压缩包内的文件清单再对一下解压出来的文件数是否一致这是验证压缩包是否完整的最快办法。Windows下不需要记命令装个7-Zip或者Bandizip右键解压到指定文件夹就行。但有一个规则两边通用先解压到纯英文路径比如D:\data\shanghai_poi_2020不要直接解压到桌面或带中文的深目录后面用ArcGIS或QGIS打开时中文路径对底层库的支持时好时坏容易出莫名其妙的打不开。2.2 解压后先盘货我给数据集建的索引表解压完不要急着双击shp先打开文件夹把里面的文件按类型列成一张索引表。这类数据包通常包含四类内容我用一张表概括文件类型扩展名作用打开方式POI矢量.shp/.dbf/.shx空间点位可叠加分析ArcGIS / QGISPOI表格.xlsx/.xls按字段筛选、透视统计Excel / WPSDEM栅格.tif/.img高程、坡度、坡向分析ArcGIS / QGIS行政区划.shp/.dbf裁剪、分区统计边界ArcGIS / QGISshp有个容易被新手忽略的规则它不是一个单独的文件而是由.shp、.dbf、.shx三个基础文件组成的文件组.shp存几何、.dbf存属性、.shx存索引。如果是带投影的文件还会多一个.prj。所以盘货时要看它是不是一个完整文件组只拷走一个.shp在别人机器上照样打不开。盘完文件类型接着要建字段字典。双击打开excel版POI把字段名列出来比如名称、地址、类别、经度、纬度、区县等。这一步看起来原始但它决定了后面你做空间连接时用哪个字段挂接。同时打开dbf属性表对比两边字段名和字段顺序是否一致。字段类型也要看一眼重点确认经纬度是数值型还是文本型是十进制度还是度分秒格式。这两个问题不查清楚第4章的导入转shp环节一定会翻车。2.3 字段摸底excel和shp里的POI字段要分开看拿到excel格式POI后先看工作表底部有几个sheet常见的布局是第一个sheet放字段说明第二个sheet放全量数据也可能按类别拆成多个sheet。我一般先用Python做一次快速扫描把列名、行数、每列的非空值数量一次打出来import pandas as pd df pd.read_excel(上海_poi_2020.xlsx, sheet_name0, nrows5) print(df.dtypes) df_full pd.read_excel(上海_poi_2020.xlsx, sheet_name0) print(总记录数:, len(df_full)) print(每列非空数:\n, df_full.count())nrows5只读前5行用于快速确认字段名和列顺序第二次全量读入后用count()检查每一列有没有大面积的缺失值。如果经纬度列存在缺值或空值转shp时那些点会被几何引擎直接丢弃但你是看不到被丢弃了多少的——所以最好在导入前就把缺值比例搞清楚。如果发现坐标字段是文本格式比如121.4737前后带着不可见空格要先清理df[lon] df[经度].astype(str).str.strip().astype(float) df[lat] df[纬度].astype(str).str.strip().astype(float)astype(str)先把所有值统一转成字符串strip()去掉首尾空格再转浮点。这步叫“清洗坐标列”等真正导图的时候如果点位飞到非洲或显示不出来十有八九就是这一步没做干净。3. 坐标系与投影对齐把三份数据放到同一张地图上3.1 先判断坐标系再动手WGS84、GCJ02还是CGCS2000这个数据包里POI、DEM、行政区划大概率不是同一套坐标系这是空间分析里最容易出问题却最不容易被发现的坑。坐标系的差异不像字段缺失那样会在日志里报错它的典型表现是“数据能打开但叠加后点位整体偏移几百米到几公里”而新手最容易忽略它直接认为是数据下载错了。拿到数据的第一个动作是先看.prj文件里的投影信息。用文本编辑器打开.prj文件里面是WKT格式的描述。常见的三种可能我列成一张表坐标系典型标识坐标量级常见来源WGS84GEOGCS[GCS_WGS_1984]经度120~122纬度30~32GPS采集、国际开放数据GCJ02无标准prj常被标成WGS84经度121.4附近偏移约200~500米国内地图平台导出CGCS2000GEOGCS[China_2000]经度120~122与WGS84差异约几十厘米国土、规划系统成果如果.prj文件缺失还有一个土办法判断把POI和行政区划同时加载进ArcMap看看点位和区县边界是否贴合。如果点在行政区范围外几百米大概率是GCJ02加密坐标被错标成了WGS84如果POI点位整体落在街区内部、和路网关系正常基本可以判断是WGS84或CGCS2000。用上海人民广场的坐标做参照也行——WGS84下大约是东经121.47、北纬31.23如果你的POI数据围绕这个值浮动不超过0.01度说明没加密如果统一偏移了0.005度以上就要警惕GCJ02。DEM栅格一般不再加密大多是CGCS2000或WGS84可直接从.tif的元信息里读。3.2 坐标对齐实操ArcGIS的Project和QGIS的warp先统一逻辑把矢量数据和DEM全部转到一个目标坐标系不要问哪个坐标系“最好”要看你的用途。如果做的是城市尺度叠加分析、出图比例尺在1:1万到1:10万之间用CGCS2000的投影坐标系最稳妥如果只是把POI点落在WGS84底图上做初步可视化全部转WGS84地理坐标系就够了不上投影还省事。ArcGIS下用ArcToolbox里的Data Management Tools - Projections and Transformations - Feature - Project输入POI图层在Output Coordinate System里选择目标坐标系比如CGCS2000 / 3-degree Gauss-Kruger zone 38——上海经度在121度附近3度带的中央经线对应120度或123度带号要选对选错了整个图会横向错位。这里的坑是很多人不清楚EPSG代码推荐查询目标坐标系的EPSG编号再填入少走弯路。QGIS里的对应操作是Vector - Data Management Tools - Reproject Layer输出图层会自带新的坐标系。栅格DEM则用Raster - Projections - Warp (Reproject)。warp参数里要注意“Resampling method”选Bilinear双线性插值因为DEM是连续地形表面用最近邻Nearest Neighbour会出现明显的阶梯状断层。对齐完成后做一次验证用ArcGIS的Identify工具随机点选10个POI点位对照底图上的建筑或道路交叉口确认点位没有出现可见偏移。如果是从GCJ02转WGS84转换并不是简单的减偏移量而是需要先做坐标系变换很多公开的地图SDK里才有对应函数。我见过有人直接用固定常数把坐标平移结果郊区点位仍然偏移大几十米——数学上完全不对别省这一步。4. 从Excel POI到可分析shp导入、投影与空间连接4.1 用Python把Excel POI转成shppandas geopandas标题里同时给了shp和excel两种格式的POI为什么要两版shp适合在GIS里做空间查询、裁剪和叠加excel适合用数据透视表做类别统计、物业类型占比、连锁品牌覆盖等常规业务分析。但很多实际工作是先从excel里筛完一批目标POI再把这批目标转成shp去做空间分析所以Excel到shp这条路是绕不开的。我一般用geopandas来做步骤简洁且可复现import pandas as pd import geopandas as gpd from shapely.geometry import Point df pd.read_excel(上海_poi_2020.xlsx) df df.dropna(subset[经度, 纬度]) geometry [Point(lon, lat) for lon, lat in zip(df[经度], df[纬度])] gdf gpd.GeoDataFrame(df, geometrygeometry, crsEPSG:4326) gdf gdf.to_crs(EPSG:3857) # 如需投影坐标系再执行 gdf.to_file(上海_poi_2020_筛选.shp, encodingutf-8, driverESRI Shapefile) print(f生成{len(gdf)}个点已导出shp)这段代码的核心就四步dropna剔除经纬度缺失的行Point构造空间几何GeoDataFrame把普通表升级为带几何的矢量表to_file写出shp。crsEPSG:4326在创建时就要指定否则后面任何空间操作都会报缺少坐标系的错误。最后写文件时给encodingutf-8是为了避免属性表中文乱码这个参数只影响dbf内部编码不影响坐标数据本身。如果你手里只有ArcGIS没有Python环境也有等价操作右键Excel文件 -Export Features或使用Excel To Table工具把它转成dBASE或地理数据库表再用Display XY Data选经纬度字段生成事件层最后Export Data导出成shp。步骤多几步但逻辑相同关键还是创建事件图层时别选错坐标字段和坐标系。4.2 空间连接与行政区裁剪DEM一张可自由出图的分析底图shp版POI拿到后最常见的操作是把POI关联到行政区划统计每个区的POI数量或类别构成。这里用不上“点对区”的拓扑计算直接做空间连接即可。ArcGIS里工具是Spatial Join目标图层选POI连接图层选行政区划匹配选项选Intersect输出结果中每条POI会带上区县代码和区县名称字段。QGIS里对应的是Join attributes by location结果同理。空间连接做完后建议把结果导出成新文件再继续分析因为空间连接生成的临时图层一旦关闭关联字段就丢失了。这一步常被忽略我自己的习惯是任何分析结果的第一时间就落盘别让临时图层在工程里裸奔。接下来是DEM的处理。30米分辨率的DEM适合做整个上海市域的缓坡分析和宏观地形起伏但如果要针对某个区分析直接用原文件做切片会非常慢正确做法是先用行政区面图层裁剪DEM。ArcGIS里用Extract by Mask输入栅格选DEM输入掩膜选行政区划面输出就是被裁剪到该区范围的高程栅格。注意这里区分两个工具Clip是按矩形范围裁剪Extract by Mask是按面形状裁剪前者的输出是外接矩形后者才是真正的行政区边界形状。很多人在这个问题上分不清导出来的DEM范围比行政区大一圈后续做填挖方分析时结果全错。QGIS里对应Raster - Extraction - Clip Raster by Mask Layer同样指定裁剪图层。裁剪后检查一下输出栅格的NoData值设置凡是落在行政区边界外的地方栅格值应为NoData而不是0否则坡度和填挖方计算会把NoData当成平地处理。4.3 清洗后的POI分类字段写回excel备份做完空间连接和裁剪POI属性表里多了行政区字段这时顺手把结果导出回excel一份作为后续做报表的底表比直接在GIS里做数据透视表顺手得多。geopandas写法result gpd.read_file(上海_poi_2020_筛选.shp) result result.drop(columns[geometry]) # 去掉几何列存excel result.to_excel(上海_poi_2020_分析底表.xlsx, indexFalse)完整空间分析工作流是用shp完成最终汇报交接用excel两种格式各有分工别试图用一种格式包打天下。这里还有个小技巧导出前先用result[区县].value_counts()看下各区的POI数量分布是否合理如果某个区的数量占比高得离谱回头查一下数据是否在空间连接时出了问题比如某个面要素存在重复边界导致多点落入。5. 避坑这个数据集的六宗最常见翻车现场5.1 解压报错分卷缺失或CRC校验失败现象解压到一半弹出“缺少分卷”或“CRC错误”压缩包被中断已解压出来的文件不完整。原因下载时传输中断或者网盘客户端没有把分卷文件全部同步到本地。解决先对比本地分卷文件大小和网盘页面展示的是否一致补下缺失卷用7z t 文件名.7z测试压缩包完整性输出Everything is Ok再用不要赌运气硬解压。5.2 shp打不开提示shapes与table records数量不匹配现象打开shp时提示“Number of shapes does not match number of table records”地图上只显示了一部分点。原因shp文件组被单独拷贝过.dbf和.shp不同步或者解压不完整。解决回到原始7z包重新完整解压如果文件名是中文改成英文文件名再打开还打不开就用ogrinfo检查文件结构确认是哪个文件损坏重新下载对应分卷。这类问题别自己手工去编辑dbf补记录越补越乱。5.3 excel里的经纬度是文本shp转出来点位全在非洲现象Excel中经纬度列显示为“121.4737E”带字母或单位用pandas读取后直接astype(float)报错。原因POI数据源在写入时把坐标拼成了带后缀的文本或者小数点是全角字符。解决先统一文本格式提取数字部分再转换。处理全角字符可以做一个整列清洗df[经度] df[经度].astype(str).str.replace(, .).str.extract(r([\d.])).astype(float)str.extract配合正则只保留下数字和小数点前后缀全部丢弃。转换完后核对取值范围经度应在120~122之间、纬度在30~32之间超出这个区间直接打印告警别让脏坐标混进后续分析。5.4 POI点整体偏移落不到行政区范围里现象POI和行政区划叠加后点位全部向东南或西北偏移几百米。原因前面第3章说的坐标系不一致——POI是GCJ02行政区划是CGCS2000或者POI是WGS84被投影工具强行按GCJ02读取。解决先各自用Identify查看坐标值确认两个图层的坐标系定义再做统一转换。记住一个关键点GCJ02是社会公开的电子地图坐标系坐标系变换不能只做平移需要先按照公共转换参数迭代计算至少要把经纬度先转成平面坐标再变换。没有现成转换工具时直接放弃让点位完美贴合道路退一步做行政区级别的统计也够用。5.5 dbf属性表中文乱码全是问号现象ArcGIS里打开POI属性表中文名称、地址字段显示为“”或者变成类似“?¨?”的乱码。原因dbf文件默认编码与ArcGIS当前区域设置不一致常见的是源数据用GBK编码写入ArcGIS按UTF-8读取。解决不要直接在ArcGIS里改配置。用Python读出来后重新以UTF-8编码写一份shp即可如果手里只有ArcGIS可以在ArcToolbox - Data Management Tools - Add Field里重建字段再从原表计算灌入虽然繁琐但有效。习惯上我现在写任何shp都强制指定encodingutf-8从源头上杜绝乱码。5.6 用面图层裁剪DEM输出一片黑或整片无值现象Extract by Mask执行成功但裁剪出的DEM在ArcMap里显示为一整块黑色或空白。原因栅格范围只有极少数像元或者输出栅格被限制在面要素外接矩形的瞬间时裁剪范围没有与DEM像元对齐产生大量NoData像元且显示比例被拉伸到异常值。解决在Extract by Mask的环境设置中把Snap Raster设为原始DEM这样输出像元会严格对齐到输入DEM网格如果仍然偏黑检查属性表里最小最大值是否正常必要时用Calculate Statistics重建栅格统计信息。黑屏多数不是数据坏了而是符号化显示没刷新而已。6. 进阶用Python给数据集做一次强制体检十分钟摸清底细分析做完之前先给整个数据集写一个体检脚本把坐标系、字段、数量、经纬度范围、行政区和DEM边界一次查明后续所有的分析工作都在这份体检报告之上做决定避免中途再来回折腾。import geopandas as gpd import pandas as pd import rasterio def check_vector(path, name): gdf gpd.read_file(path) print(f[{name}] 要素数: {len(gdf)}, 坐标系: {gdf.crs}) print(f范围: {gdf.total_bounds}) return gdf def check_raster(path, name): with rasterio.open(path) as src: print(f[{name}] 像素: {src.width}x{src.height}, 坐标系: {src.crs}) print(f范围: {src.bounds}, NoData: {src.nodata}) gdf_poi check_vector(上海_poi_2020.shp, POI) gdf_district check_vector(行政区划.shp, 行政区) check_raster(上海_dem_30m.tif, DEM)脚本虽短输出却足以支撑判断如果total_bounds中南边界大于31.3度说明坐标可能混入了GCJ02的非标准范围如果DEM的宽度和高度比例明显不符合经纬度跨度比例说明它可能已经做过投影或重采样。这些信息不需要打开GIS就能拿到效率差得很明显。我自己的习惯是每次拿到外部数据集先跑一遍这种体检把结果存成一个data_profile.txt放在数据目录下接下来的所有分析步骤都对照它来定参数。比如第3章的转换目标、第4章的行政区分组都要参考这份报告决定而不是打开软件边看边试。数据集的坑基本都藏在边界值、坐标系和字段类型里这三个点查明白后面的分析就稳了。坐标范围确认后再用行政区边界对POI做一次空间过滤剔除落到辖区外的孤立点得到干净的分析底图。这套流程走下来整个数据集的底细就完全掌握在手里后续无论是转3dtiles做可视化还是做渔网统计POI密度都能直接拿现成的数据源继续。希望这套从解压到体检的路径能帮你少走弯路把时间留给真正的分析工作。本文还有配套的精品资源点击获取