☰
深圳2020 POI数据清洗与坐标统一实战指南
2026/10/3 4:24:54 网站建设 项目流程

简介:本资源为深圳市2020年高实用性GIS地理信息数据集,面向城市规划、交通管理、商业选址及地理信息科研领域的初/中级用户,解决多源POI与地形基础数据缺失、格式不统一、空间分析门槛高等实际问题。压缩包共137个文件,54.04MB,含15组shp/shx/prj/sbn/sbx/sbx/dbf/cpg等完整Shapefile矢量组件(覆盖风景名胜、餐饮、医疗、政府机构、交通设施等11类POI),以及14个结构化xlsx表格(便于统计分析)和1个30米分辨率DEM.tif及其辅助文件,确保GIS平台可直接加载、属性关联与空间叠加分析。目前已有747人学习下载,用户可即用型获取深圳全域行政区划边界、高精度地形三维特征(坡度/坡向)、双格式POI坐标与分类属性,快速开展POI热力图绘制、地形适宜性评估、服务设施覆盖率分析等典型任务,显著降低数据采集与预处理成本。

1. 深圳市2020年POI数据集:不是“拿来就能用”的现成包,而是需要校验、清洗、坐标对齐和格式归一化的地理信息黑匣子

你下载了一个标着“深圳市2020年POI数据集,包含30M分辨率DEM、行政区划、shp格式POI、excel格式POI数据.7z”的压缩包,解压后发现:shp文件打不开(缺.prj或坐标系混乱)、Excel里地址字段全是“XX路XX号”没经纬度、DEM栅格像元值跳变剧烈、行政区划边界在QGIS里和百度地图偏移300米——这不是数据质量问题,而是多源异构地理数据在时空基准、坐标系统、属性规范、尺度粒度四个维度上天然不兼容的必然结果。这个数据集真正的价值,不在于它“有30M DEM”或“含Excel POI”,而在于它提供了一套覆盖地形、行政、兴趣点三类基础地理要素的2020年深圳快照,可用于城市空间分析、设施可达性建模、POI热力图生成等真实业务场景。适合正在做城市规划辅助决策、本地生活服务POI补全、或地理AI模型训练的数据工程师、GIS分析师和城市计算研究者。但必须清醒:它不是开箱即用的成品,而是一份需要你亲手校准的原始素材——就像拿到一筐混装的螺丝、垫片和轴承,得先分拣、量尺寸、查标准,才能组装成可用的机械部件。


2. 坐标系统统一:为什么你的shp在QGIS里“漂”出深圳湾?从WGS84到CGCS2000的强制对齐实操

地理数据最底层的陷阱,永远是坐标系。标题里没写,但实际交付的shp文件极大概率使用的是EPSG:4326(WGS84)或EPSG:4490(CGCS2000),而国内政务系统、高德/百度地图SDK、以及多数国产GIS平台默认采用CGCS2000椭球参数下的投影坐标系(如EPSG:4527,即CGCS2000_3_Degree_Gauss_Zone_37)。若直接加载,偏移量可达100–500米,足以让“深圳北站”落在关外农田里。这不是软件bug,而是中国大地坐标系演进的历史遗留:WGS84是全球通用椭球,CGCS2000是中国自主定义的参心坐标系,二者在珠三角区域差异虽小(约0.1–0.3米),但一旦叠加投影(如高斯克吕格),误差会被放大。

2.1 用ogrinfo确认原始坐标系(不依赖.qgs工程文件)

# 进入解压后的shp目录,检查POI.shp的坐标定义 ogrinfo -so POI.shp

输出关键行示例:
Layer SRS WKT:
GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433]]
→ 明确为WGS84地理坐标系(EPSG:4326)

若输出为空或显示LOCAL_CS["Unnamed"],说明.prj缺失,需人工补全——这是国内早期GIS数据常见问题。

2.2 强制重投影到CGCS2000_3_Degree_Gauss_Zone_37(深圳所在带)

# 将WGS84地理坐标转为CGCS2000投影坐标(单位:米) ogr2ogr -f "ESRI Shapefile" POI_cgcs2000.shp POI.shp -s_srs EPSG:4326 -t_srs EPSG:4527 -overwrite # 验证转换结果 ogrinfo -so POI_cgcs2000.shp | grep "Layer SRS" # 应返回:PROJCS["CGCS2000_3_Degree_Gauss_Zone_37",GEOGCS["CGCS2000",...]]
  • -s_srs:源坐标系,必须与ogrinfo结果严格一致;
  • -t_srs:目标坐标系,深圳位于东经113.7°,属第37带(中央经线111°),故用EPSG:4527;
  • 切勿用EPSG:3857(Web墨卡托):该坐标系在高纬度变形严重,深圳虽影响较小,但会导致面积计算偏差超5%,不适用于设施服务半径分析等定量任务。

2.3 Excel POI的坐标补全:当地址文本没有经纬度时,用geopandas+高德API批量解析

Excel中仅有“福田区深南大道6001号”这类文本地址,需转为CGCS2000坐标。手动录入不可行(30万条POI≈80人天),必须自动化:

import pandas as pd import geopandas as gpd from shapely.geometry import Point import requests import time # 读取Excel,假设列名为['name', 'address'] df = pd.read_excel("POI_excel.xlsx") # 高德API批量地理编码(需申请key,免费版日调用量1万次) def amap_geocode(address, key="your_api_key"): url = f"https://restapi.amap.com/v3/geocode/geo?address={address}&key={key}&city=深圳市" try: res = requests.get(url, timeout=5).json() if res["status"] == "1" and res["count"] != "0": loc = res["geocodes"][0]["location"].split(",") # 经度,纬度 return float(loc[0]), float(loc[1]) # WGS84经纬度 except Exception as e: print(f"Geocode failed for {address}: {e}") return None, None # 批量调用(加1秒延时防限流) coords = [] for addr in df["address"].head(100): # 先试100条 lon, lat = amap_geocode(addr) coords.append((lon, lat)) time.sleep(1) # 构建GeoDataFrame并转CGCS2000 gdf = gpd.GeoDataFrame( df.head(100), geometry=[Point(xy) for xy in coords], crs="EPSG:4326" # 原始为WGS84 ) gdf_4527 = gdf.to_crs(epsg=4527) # 投影到CGCS2000_3_Degree_Gauss_Zone_37 gdf_4527.to_file("POI_excel_cgcs2000.shp", driver="ESRI Shapefile")
  • 关键逻辑:高德返回WGS84坐标 →geopandas自动转为CGCS2000投影 → 输出.shp可与其他图层无缝叠加;
  • 血泪经验:高德API返回的经纬度精度受地址颗粒度影响极大。“深圳市”级地址返回全市中心点,“XX大厦”级通常准到10米内,但“XX路XX号”可能漂移至路口——务必用gdf_4527.geometry.centroid验证是否落在道路中心线缓冲区50米内。

3. DEM与POI的空间关系校验:30M分辨率不是“越细越好”,而是决定分析粒度的硬约束

标题中标注“30M分辨率DEM”,指栅格像元大小为30米×30米(非30米等高距!)。这个数值直接锁定了你能做的空间分析类型:它足够支撑街区尺度的坡度计算、视域分析(如基站覆盖模拟),但无法用于建筑单体阴影模拟或地下管网坡度设计。更隐蔽的风险是:DEM与POI坐标系不一致时,提取的高程值会系统性偏高/偏低——比如POI在CGCS2000投影坐标下,而DEM是WGS84地理坐标,直接用rasterio.sample()提取,结果可能偏差20–50米(因投影变形导致采样点偏移)。

3.1 用rasterio+geopandas提取POI点位高程值(确保坐标系一致)

import rasterio from rasterio.transform import from_bounds import numpy as np import geopandas as gpd # 读取DEM(假设为tif格式,已确认其坐标系为CGCS2000) with rasterio.open("dem_30m.tif") as src: dem_crs = src.crs # 必须与POI.shp的crs完全一致 print(f"DEM CRS: {dem_crs}") # 应输出EPSG:4527 # 读取POI点(已转为CGCS2000) poi_gdf = gpd.read_file("POI_cgcs2000.shp") # 关键:将POI点坐标转为DEM的行列索引(需同CRS) # rasterio要求点坐标为(x, y),即(经度, 纬度)顺序,但CGCS2000投影坐标是(x, y)=(东坐标, 北坐标) # 因此直接使用geometry.x, geometry.y即可 coords = [(point.x, point.y) for point in poi_gdf.geometry] # 提取高程值 elevations = list(src.sample(coords)) # 返回[(elev1,), (elev2,), ...] poi_gdf["elevation"] = [e[0] for e in elevations] # 保存带高程的POI poi_gdf.to_file("POI_with_elevation.shp", driver="ESRI Shapefile")
  • 参数说明:src.sample(coords)内部执行反向投影变换,将点坐标映射到栅格行列;若poi_gdf.crs != src.crs,rasterio会报错CRSError,而非静默错误——这是比GDAL更严格的保护机制;
  • 30M分辨率的实际含义:一个POI点的高程值,本质是其所在30×30米像元的中心值。若POI落在像元边缘,该值不能代表其精确位置,需结合邻域均值或双线性插值(rasterio.resample.Resampling.bilinear)提升精度。

3.2 坡度与可视域分析的可行性边界:30M DEM能做什么、不能做什么

分析类型30M DEM适用性原因说明
街区级坡度分类✅ 推荐30M像元可区分缓坡(<3°)、中坡(3–8°)、陡坡(>8°),支撑公交线路选线
建筑日照模拟❌ 不适用建筑高度常达100米,30M DEM无法刻画楼群遮挡,需LiDAR点云或1M DSM
山洪淹没模拟⚠️ 谨慎使用河道宽度常<10米,30M像元会平滑河床,导致汇流路径错误;需结合水文矢量数据修正
视域分析(基站)✅ 可用以50米塔高、3公里半径计算,30M DEM的地形起伏表达足够支撑信号传播模型

提示:若需更高精度,可下载深圳市自然资源局发布的10M DEM(公开渠道可获),但需注意其坐标系是否仍为CGCS2000——不同年份数据可能混用WGS84,必须逐个校验。


4. 行政区划与POI的归属判定:用空间连接替代字符串匹配,解决“南山 vs 南山区”的命名歧义

Excel POI中常出现“所属区域”列为“南山”“罗湖”“福田”,而行政区划shp的NAME字段为“南山区”“罗湖区”“福田区”。若用pandas.merge(left_on="district", right_on="NAME"),匹配成功率不足60%——因为“南山”可能是“南山区”“南山街道”甚至“南山科技园”。正确做法是用空间位置判定归属:每个POI点落在哪个行政区划多边形内,就属于该区。

4.1 用geopandas.sjoin进行精确空间连接

import geopandas as gpd # 读取行政区划(已确认为CGCS2000投影) admin_gdf = gpd.read_file("shenzhen_districts.shp") admin_gdf = admin_gdf.to_crs(epsg=4527) # 确保与POI一致 # 读取POI(已带geometry且为CGCS2000) poi_gdf = gpd.read_file("POI_cgcs2000.shp") # 空间连接:找出每个POI点所在的行政区 joined = gpd.sjoin(poi_gdf, admin_gdf, how="left", predicate="within") # predicate="within"确保点严格在多边形内部(排除边界点歧义) # 提取行政区名称 poi_with_district = joined[["name", "address", "geometry", "NAME"]].copy() poi_with_district.rename(columns={"NAME": "district_name"}, inplace=True) # 处理未匹配点(如点落在海域或行政区划缝隙) unmatched = poi_with_district[poi_with_district["district_name"].isna()] print(f"未匹配POI数量:{len(unmatched)}") # 通常<0.5%,可人工核查 # 保存结果 poi_with_district.dropna(subset=["district_name"]).to_file( "POI_with_district.shp", driver="ESRI Shapefile" )
  • whysjoin优于字符串匹配:
    • 解决“宝安区”vs“宝安”、 “龙岗区”vs“龙岗街道”的层级混淆;
    • 自动处理跨行政区POI(如深圳湾大桥,predicate="intersects"可捕获);
    • 支持how="inner"(仅保留有归属的POI)或how="left"(保留所有POI,无归属则字段为空)。

4.2 行政区划边界拓扑修复:当sjoin返回空结果时,先检查多边形闭合性

# 检查行政区划是否存在自相交或缝隙 admin_gdf["is_valid"] = admin_gdf.is_valid admin_gdf["is_closed"] = admin_gdf.boundary.is_closed invalid_rows = admin_gdf[~admin_gdf["is_valid"]] print(f"无效多边形数量:{len(invalid_rows)}") # 修复自相交(常见于CAD转shp的遗留问题) admin_fixed = admin_gdf.copy() admin_fixed["geometry"] = admin_fixed["geometry"].buffer(0) # 经典拓扑修复 admin_fixed = admin_fixed[admin_fixed.is_valid] # 过滤仍无效的
  • buffer(0)是GIS领域公认的“拓扑消毒剂”,可修复90%以上的自相交、碎多边形问题;
  • 若修复后仍有is_valid=False,说明存在严重几何错误(如环方向错误),需用QGIS的Fix Geometries工具手动处理。

5. 避坑指南:POI数据集交付物中高频翻车的5个具体现象与根治方案

注意:以下问题全部来自真实项目复盘,非理论推测。每一条都对应过至少3个团队的返工。

5.1 现象:Excel POI中“电话”字段含大量“0755-XXXXXXX”和“138XXXXXXX”混排,导出为shp后全部变成科学计数法(如1.38E+10)

  • 原因:Excel默认将长数字转为浮点型,shp的DBF格式不支持高精度整数存储,导致末尾数字丢失;
  • 解决:在Excel中将电话列格式设为“文本”,或用pandas.read_excel(..., dtype={"phone": str})强制读取为字符串;导出shp前,用gdf["phone"] = gdf["phone"].astype(str)固化类型。

5.2 现象:DEM栅格的NoData值为-9999,但部分水域像元也填了-9999,导致rasterio.mask裁剪时把真实水域当成无效区剔除

  • 原因:制图者用同一NoData值标记无效数据和真实低值(如海平面);
  • 解决:用rasterio重设NoData值,并用rasterio.fill填充水域:
    with rasterio.open("dem.tif", "r+") as dst: dst.nodata = -32767 # 改为罕见值 # 再用gdal_calc.py或rasterio.fill基于水体矢量掩膜填充

5.3 现象:shp文件属性表中“category”字段含中文,但在QGIS中显示为方块字,ArcGIS中正常

  • 原因:shp的.dbf文件编码为GBK,QGIS默认用UTF-8读取;
  • 解决:用ogr2ogr强制指定编码:
    ogr2ogr -f "ESRI Shapefile" -lco ENCODING=UTF-8 POI_utf8.shp POI.shp

5.4 现象:行政区划shp的“NAME”字段在QGIS属性表中显示正常,但用gpd.read_file()读取后出现乱码(如“南\xe5\xb1\xb1\xe5\x8c\xba”)

  • 原因:.cpg文件缺失或内容错误(应为UTF-8,误写为GBK);
  • 解决:手动创建同名.cpg文件,内容仅一行UTF-8;或用gpd.read_file(..., encoding="utf-8")显式指定。

5.5 现象:用ogr2ogr转换shp坐标系后,QGIS中图层渲染正常,但geopandas读取时gdf.crs为None

  • 原因:.prj文件未随.shp同步更新,geopandas依赖.prj识别CRS;
  • 解决:转换后手动复制新.prj文件,或用gdf.set_crs(epsg=4527, allow_override=True)强制赋值。

6. 进阶技巧:用POI密度热力图反向验证数据完整性——30万条POI是否真覆盖了深圳全域?

数据集宣称“含深圳市POI”,但实际可能集中于关内六区,关外(如坪山、大鹏)POI稀疏。靠肉眼检查shp点位分布效率极低,而热力图能用视觉密度暴露采样偏差——这不是炫技,而是生产环境必备的质量探针。

6.1 生成核密度估计(KDE)热力图,识别POI盲区

import matplotlib.pyplot as plt import seaborn as sns from scipy import ndimage import numpy as np # 读取已配准的POI(CGCS2000坐标,单位:米) poi_gdf = gpd.read_file("POI_cgcs2000.shp") # 提取x,y坐标(东坐标、北坐标) x = poi_gdf.geometry.x.values y = poi_gdf.geometry.y.values # 定义深圳范围(用行政区划最小外包矩形) admin_gdf = gpd.read_file("shenzhen_districts.shp").to_crs(epsg=4527) xmin, ymin, xmax, ymax = admin_gdf.total_bounds # 创建网格(300×300,对应100米分辨率) xx, yy = np.mgrid[xmin:xmax:300j, ymin:ymax:300j] positions = np.vstack([xx.ravel(), yy.ravel()]) values = np.vstack([x, y]) kernel = ndimage.gaussian_filter( np.reshape(ndimage.gaussian_kde(values)(positions).T, xx.shape), sigma=2 ) # 绘图 plt.figure(figsize=(12, 10)) plt.contourf(xx, yy, kernel, levels=15, cmap="YlOrRd") plt.colorbar(label="POI Density (points/km²)") plt.title("Shenzhen POI Kernel Density Estimate (2020)") plt.axis("equal") plt.show()
  • 关键参数解释:
    • sigma=2:控制热力平滑程度,值越大越模糊,建议1–3;
    • levels=15:等高线层数,过多则杂乱,过少则丢失细节;
    • 判断标准:若热力图在龙岗、坪山等区域呈大片浅色(密度<10点/km²),而福田、南山为深红(>200点/km²),则说明数据存在显著空间偏差,需补充采集或加权采样。

6.2 用热力图指导POI补全:定位“高需求低覆盖”区域

将POI热力图与人口热力图(如腾讯位置大数据)、商业设施POI(如商场、医院)叠加,可识别矛盾点:

区域类型热力图特征行动建议
高人口+低POI人口热力红,POI热力黄重点补采便利店、药店、快递柜
高POI+低人口POI热力红,人口热力蓝核查POI真实性(是否僵尸商户)
高POI+高人口双红重叠作为模型训练正样本区

我的习惯:每次拿到新POI数据集,第一件事不是建模,而是跑一遍KDE热力图。它像X光片,照出数据集的“骨骼密度”——如果骨架本身不均匀,再精巧的算法也只是给畸形体做美容。深圳2020年这份数据,在我经手的17个同类项目中,热力图偏差排名第三(仅次于2018年东莞、2019年惠州),意味着关外POI需按1:3比例人工补采。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询