2025分省分市POI数据全流程实战:清洗、坐标转换与PostGIS入库 今年开年的时候我一直在找一份能覆盖全国范围、颗粒度又足够细的POI点位数据因为手上好几个项目都卡在这一环——做连锁品牌的选址评估需要知道一个商圈里餐饮和购物的真实分布做城市更新前期调研得摸清片区内公共服务和生活设施的底数还有给物流团队做网格化配送规划也需要把末端驿站的密度分布看清楚。结果市面上的数据要么是几年前的旧版本要么只有大城市的局部范围要么字段少得可怜连最基本的行政区划编码都不全。后来辗转弄到了一份2025年版的中国分省/分市POI点位数据集用下来整体质量相当能打。这篇文章我就把自己拿这份数据从处理到落库再到实际分析的全过程包括踩过的坑、改过的坐标算法、验证过的质量清单完整写一遍给同样在做地理数据分析的朋友做个参考。这套数据最适合三类人一是做商业分析、市场研究的小伙伴需要快速了解任意区域的业态分布二是GIS开发或后端工程师打算搭建自己的地理服务能力需要一个干净可靠的底图数据源三是读城市规划、人文地理方向的研究生做论文研究时缺一套能跑空间统计的实证数据。1. 2025年版分省/分市POI数据集的价值它到底解决什么问题1.1 POI点位数据到底是什么POI是Point of Interest的缩写直译过来就是“兴趣点”。在实际的地理信息领域它指的是地图上那些具有真实意义的点状地理实体——餐馆、酒店、商场、学校、医院、加油站、各种办事机构甚至公交站牌和充电桩都算POI。每个点通常包含名称、地址、经纬度、分类等属性本质上是把现实世界里“这里有什么”这件事转成结构化的空间数据让计算机可以批量计算、筛选和可视化。可能很多不接触地理信息的人会混淆一件事搜“POI”的时候经常会跑出一堆Apache POI操作Word和Excel表格的Java开发教程。这里必须先说清楚本文讨论的POI是地理信息系统里的兴趣点和办公文档处理没有关系。Apache那个POI库是处理.docx和.xlsx文件的做Java开发的朋友千万别搞混了。回到地理数据这个POI它的核心价值在于“位置属性”的组合。一条记录如果只有经纬度那只是一堆坐标点没什么分析价值但如果给它挂上分类、名称、所在城市它立刻就能回答很多现实问题。比如定位一个候选门店位置后计算周边1公里范围里有多少家同品类门店这个数就是选址决策的重要参考。我拿到的这份2025年版数据在这一点上做得尤其到位。它不单是记录了多少万个点而是每一条都带完整的省、市、区县信息可以直接按行政区域切分、统计和对比。这也是我推荐大家优先选“分省/分市”版本而不是一次性全量导出的原因——后面我会详细说。1.2 分省/分市拆分带来的三个直接好处第一数据处理压力小很多。全中国几千万条POI记录如果塞成一个文件光读取就能把普通电脑的内存挤爆。即便能打开后续做筛选、聚合、空间连接每一步操作都在挑战性能极限。但按省或按市拆开之后每个文件从几万到几十万条不等用pandas处理时流畅很多需要哪个城市的数据就直接加载哪个文件。第二便于按区域迭代更新。POI数据不是一成不变的——每个季度都有新开业的商场、搬迁的店铺、竣工的地铁站。分省/分市的数据在维护和更新时可以只替换变化的省份或城市文件而不需要把整个数据库推倒重来。这种增量式管理在真实业务中非常实用。第三权限和成本更好控制。如果你是在大型企业或研究机构工作数据资产的审批、分发通常按城市或省域进行。省级粒度已经能让多数区域型研究项目直接开工市级粒度则进一步满足重点城市群的深度分析。这个粒度设计不只是技术选择更是管理上的现实考量。1.3 2025年版本相比往年数据的几个关键升级从数据内容上看2025年版有几个非常有价值的增量。首先是充电桩、换电站等新能源基础设施POI被单列出来并且细化了快充、慢充、换电等子类。这个变化反映的是新能源车渗透率快速提升的现实。去年我做一个关于新能源汽车补能设施可达性的分析就因为没有统一口径的充电桩数据前前后后整合了很多个来源。数据里有单独的充电桩分类对这类研究是巨大的便利。其次是县域覆盖度明显提升。往年数据在三四线城市、县城区域经常质量掉链子——要么该有的POI完全没有要么点位坐标偏移严重。2025年版在这方面的表现要好不少我随机抽取了几个中部省份的县级城市核对主城区内的餐饮和住宿类点位覆盖率比往年版本高出不少。第三是字段里增加了不少辅助属性。比如部分POI带有营业状态标记——营业中、暂停营业、已关闭这个信息在做存量分析时特别有价值。很多市场需求测算实际上针对的是“还在营业的店铺”如果数据里不剔除已关闭的门店分析结论会严重失真。2. 数据剖析字段结构、分类体系与坐标系2.1 核心字段结构与含义这份数据因为是按分省/分市组织的所以每条记录的行政区划信息都比较完整。我用下来认为最重要的字段是这几类唯一标识每条POI都有一个全局唯一ID一般用字符串表示。这个ID在去重、关联、增量更新时是命根子没有唯一ID的数据几乎没法维护。名称与地址POI名称是必填字段地址作为辅助字段。地址的完整度在不同城市差异比较大一线城市的地址结构化程度明显好于小城市。经纬度坐标用于空间定位通常是火星坐标系(GCJ-02)。这个细节极其关键后面我会专门展开讲。行政编码省份代码、城市代码、区县代码。这套编码一般基于国家行政区划标准。有了编码字段做筛选和关联效率会高很多。大类与中类分类POI分类是分析中最常用的维度。分类体系的合理性直接决定分析能不能做下去。我拿到的文件还带了一列数据来源标记区分了不同渠道聚合的记录。这个字段看似不起眼实际在数据清洗时用处很大可以快速识别来源可靠性并针对性修正。2.2 分类体系可从一级类目看懂这座城市2025年版数据的分类体系大致覆盖了餐饮、购物、住宿、景点、科教、医疗、交通、金融、生活服务、体育休闲等常见大类。在大类之下还细分了多个中类比如餐饮大类下面会区分中餐厅、西餐厅、快餐、咖啡厅、茶饮等零售大类里则会细分超市、便利店、服装店、数码店等。这个分类精细度对真实业务分析已经足够。举个例子如果我想评估一个新商场项目的竞争力只需要筛选出它三公里范围内所有零售类的子类目按不同品类汇总数量和档次就能看出周边的竞争强度和空白机会。分类太粗会看不到结构性的差异分得太细又容易造成样本稀疏当前这种“大类中类”的两层设计是比较务实的粒度。我建议大家在使用时先花点时间梳理一遍分类体系搞清楚自己关心的业务场景对应哪些中类。很多分析项目做到中途推倒重来不是因为算法不行而是因为一开始分类口径没定清楚。2.3 坐标系问题为什么点位总是偏几百米做中国地理数据的所有人都逃不过坐标系这个大坑。国际上通用的坐标系是WGS-84而国内绝大多数地图平台对外输出的坐标是GCJ-02俗称“火星坐标”。两者之间是经过了非线性偏移处理的直接用GCJ-02辣到WGS-84的底图上渲染会有几十米到几百米的偏移。至于BD-09则是百度地图在其基础上又做了一层二次偏移。如果数据是从不同平台采集的必须先统一坐标系再使用否则同一栋楼在不同来源的记录里会显示成两个相距几百米的点。所以在拿到2025年版POI数据时我做的第一件事就是确认坐标系的定义。这份数据的主坐标是GCJ-02这是国内主流的默认选择绝大多数地图API返回的数据都是这个坐标系。如果你的分析要用在需要WGS-84的国际工具链或者GPS设备上就要自己做转换。关于坐标转换算法网上有很多公开的数学方法。我建议用经过大量实测验证的版本不要自己在网上找一段没验证过的代码直接用。坐标转换不是简单的加减运算涉及经纬度的非线性计算一个参数写错就会导致区域性的偏移。3. 实操记录2025年POI数据的清洗、转换与入库全流程3.1 数据清洗的关键步骤拿到数据后我一般先做一遍完整性检查——检查字段数量是否齐全数据行数是否符合预期。接下来重点检查几个字段经纬度是否有缺失或明显越界值、行政区划字段是否统一规范、POI名称是否有异常的空值。城市名和编码不一致是高频问题比如“北京市”写成“北京”“张家界”的行政区划代码在不同来源里可能不同。处理规则是优先以国家行政区划标准为准把所有城市名称统一映射到标准名称和标准编码。为了稳妥我还会对地址字段做正则清洗把不规范的换行、空格、多余字符清理掉。清洗过一轮后我会做去重。去重不能只看名称是否相同而是要“名称地址分类经纬度”综合判断。两个同名且同地址的点大概率是重复数据经纬度完全相同的两个不同名称的点一般也是重复采集。判断逻辑需要根据数据质量灵活调整阈值严格去重可能误删宽松又会有漏网的。3.2 坐标转换脚本GCJ-02转WGS-84实操示例前面说了这数据的主坐标系是GCJ-02。如果你需要将其转成WGS-84可以用下面这个经过验证的Python脚本执行批量转换import math import pandas as pd x_pi 3.14159265358979324 * 3000.0 / 180.0 pi 3.1415926535897932384626 a 6378245.0 ee 0.00669342162296594323 def _transform_lat(lng, lat): ret -100.0 2.0 * lng 3.0 * lat 0.2 * lat * lat 0.1 * lng * lat 0.2 * math.sqrt(math.fabs(lng)) ret (20.0 * math.sin(6.0 * lng * pi) 20.0 * math.sin(2.0 * lng * pi)) * 2.0 / 3.0 ret (20.0 * math.sin(lat * pi) 40.0 * math.sin(lat / 3.0 * pi)) * 2.0 / 3.0 ret (160.0 * math.sin(lat / 12.0 * pi) 320 * math.sin(lat * pi / 30.0)) * 2.0 / 3.0 return ret def _transform_lng(lng, lat): ret 300.0 lng 2.0 * lat 0.1 * lng * lng 0.1 * lng * lat 0.1 * math.sqrt(math.fabs(lng)) ret (20.0 * math.sin(6.0 * lng * pi) 20.0 * math.sin(2.0 * lng * pi)) * 2.0 / 3.0 ret (20.0 * math.sin(lng * pi) 40.0 * math.sin(lng / 3.0 * pi)) * 2.0 / 3.0 ret (150.0 * math.sin(lng / 12.0 * pi) 300.0 * math.sin(lng / 30.0 * pi)) * 2.0 / 3.0 return ret def gcj02_to_wgs84(lng, lat): if out_of_china(lng, lat): return [lng, lat] dlat _transform_lat(lng - 105.0, lat - 35.0) dlng _transform_lng(lng - 105.0, lat - 35.0) radlat lat / 180.0 * pi magic math.sin(radlat) magic 1 - ee * magic * magic sqrtmagic math.sqrt(magic) dlat (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi) dlng (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * pi) mglat lat dlat mglng lng dlng return [lng * 2 - mglng, lat * 2 - mglat] def out_of_china(lng, lat): return not (lng 73.66 and lng 135.05 and lat 3.86 and lat 53.55) df pd.read_csv(poi_2025_beijing.csv) df[wgs_lng], df[wgs_lat] zip(*df.apply(lambda row: gcj02_to_wgs84(row[lng], row[lat]), axis1)) df.to_csv(poi_2025_beijing_wgs84.csv, indexFalse)提示转换前先把数据备份一份。坐标转换是不可逆过程中存在精度损失的操作前务必确认原数据稳妥保存。转换完成后也要做效果验证。最简单的方法是把某几个熟悉地标的点位在新的坐标系下放到卫星底图上核对肉眼确认位置是否落在了正确建筑物上。如果还有几十米的偏差需要检查原始坐标到底是BD-09还是ACJ-02——直接把BD-09当成GCJ-02转换结果就是偏的。3.3 写入PostGIS并建立索引对于千万级规模的POI数据仅靠CSV文件来管理和分析已经远远不够了。我的建议是导入PostgreSQL PostGIS这是开源栈里做空间数据分析最成熟的组合之一。PostGIS可以建空间索引空间查询性能比纯Python循环高几个数量级。导入的第一步是创建一张带有geometry列的表然后通过命令行或数据库工具把清洗好的CSV批量灌入。我一般会先建一张原始表按普通字段存储再用一条SQL将经纬度转换成geometry类型并加上空间索引CREATE TABLE poi_2025 ( id VARCHAR(32), name VARCHAR(255), address TEXT, province VARCHAR(32), city VARCHAR(64), district VARCHAR(64), category VARCHAR(32), subcategory VARCHAR(32), gcj_lng NUMERIC(10, 6), gcj_lat NUMERIC(10, 6), wgs_lng NUMERIC(10, 6), wgs_lat NUMERIC(10, 6), status VARCHAR(16) );数据导入完成后创建geometry字段和空间索引ALTER TABLE poi_2025 ADD COLUMN geom geometry(Point, 4326); UPDATE poi_2025 SET geom ST_SetSRID(ST_MakePoint(wgs_lng, wgs_lat), 4326); CREATE INDEX idx_poi_2025_geom ON poi_2025 USING GIST (geom);有了空间索引之后很多分析效率立竿见影。比如要统计某个商圈周边500米内的餐饮门店一条SQL语句XX毫秒级别就能出结果这在纯Python环境下难以想象。4. 常见问题与排查技巧实操中的那些坑4.1 坐标偏差差了几百米到底是谁的锅我收到过不少朋友反馈说自己拿POI数据和GPS轨迹对上时发现点位差了几百米。遇到这种情况优先检查坐标系是不是没统一。GPS设备直接采集的坐标是WGS-84而POI数据里大量是GCJ-02如果直接混用不转换偏差是必然的而且这个偏差在不同区域还会变化没法用一个固定的偏移值去修正。排查的方法是随机抽取几个点位在在线地图或者卫星影像底图上人工核对一下。如果偏差主要集中在某个编码区间说明可能是数据生产时的系统性问题如果偏差方向随机说明可能是个别点位采集精度差。还有一个容易忽略的情况数据库中保存坐标时字段类型使用了浮点数但我没约束精度。在导出和导入过程中精度丢失也会造成微小偏移。虽然通常只有几米但涉及高精度分析时还是要留意。4.2 分类字段对不上的问题不同来源的数据分类体系可能天差地别。有的用“餐饮服务”有的用“餐饮类”有的干脆用代码“050000”。如果你要做跨数据源比对建议先定义一套自己的统一分类口径再建立映射表把各来源的分类对号入座。一份映射表的典型结构如下原始分类原始编码统一分类中餐厅050101餐饮/中餐火锅店050102餐饮/火锅快餐店050103餐饮/快餐商场060101购物/商场映射表建好后用一段脚本批量更新数据库字段即可。这个步骤看起来简单但实际价值极大——没有统一分类口径后续所有统计分析都是各说各话。4.3 数据时效性怎么判断2025年版数据新不新拿到今年的数据也不能默认所有点位都是这个月的最新状态。POI数据通常从最活跃的商业类目开始更新餐饮、零售、酒店的更新频率最高而部分科教、基础设施类POI几个月不更新也正常。验证时效性的快捷方法是挑选几个已知近期开业或关闭的地点去数据里检索确认。比如上半年新开了一个大型购物中心如果这份数据里能查到它的POI记录说明商业类目至少更新到了开业时间点附近。反过来如果发现数据里还有大量“已关闭”标记但实际已经营业的门店说明还有延迟。我习惯在分析报告的数据说明部分记录下数据版本号和校验日期这样能保证自己层过几个月回头看时还记得当时用的是哪份数据、覆盖到何时。4.4 再次提醒不要和Apache POI混淆搜索资料时经常看到开发者混用POI的概念。Apache POI是Java生态中操作Office文档的库通过它修改Word表格单元格宽度之类需求走的是另一个技术路线。地理信息领域的POI数据是给地图、空间分析用的两者除了缩写相同没有任何关系。做GIS分析时如果有人给你发一段“XSSFExportToXml”的代码不用怀疑他就是发错人了。5. 直接可用三个从数据到结论的落地场景5.1 快速算出某商圈餐饮业态密度做连锁咖啡品牌选址时我拿到一家候选门店的地址坐标后会立刻算几个数1公里和2公里范围内的咖啡厅、茶饮店、甜品店数量以及中餐厅数量作为潜在客流参考。在PostGIS里写一条SQL就能完成SELECT count(*) FILTER (WHERE subcategory 咖啡厅) AS coffee_cnt, count(*) FILTER (WHERE subcategory 茶饮店) AS tea_cnt, count(*) FILTER (WHERE subcategory 中餐厅) AS restaurant_cnt FROM poi_2025 WHERE ST_DWithin(geom, ST_SetSRID(ST_MakePoint(116.397, 39.909), 4326)::geography, 2000);结果是20-40毫秒出数完全满足即时查询的需求。以前做类似分析要靠人工走查和网络搜索一个城市要花好几天现在换到数据驱动后一上午能看几十个候选点位。5.2 结合道路数据做门店覆盖分析门店规划不只是看POI相互的距离。要评估一个仓储网点的配送覆盖能力通常还需要结合道路网络计算驾车可达范围。分省/分市POI数据在这里发挥了底图层作用——把周边的社区、写字楼、商场都作为需求点再配合道路数据算出等时圈。比如要规划前置仓先把要覆盖区域内所有住宅小区POI找出来再算出3公里30分钟内的配送可达点数小区覆盖率高不高一目了然。这套方法论在各家即时零售公司里其实已经很成熟核心差异往往就在于需求点的数据质量。2025年版数据在小区、写字楼这类居住办公类POI上的覆盖率明显偏高做城市级覆盖分析时很有底气。5.3 城市活力评估POI密度暗含的规律POI密度分布其实可以粗略反映一个城市的空间结构和商业活力。我做城市商圈研究时经常把某个区域的食、住、行、游、购、娱各项POI的数量和密度拿出来做聚类很快就能找到中心商圈、次级商圈和社区商业中心的分布特征。有时候我把POI密度叠加城市夜间灯光数据看会发现一个有趣规律夜间灯光较高的区域POI密度通常也不低但有些区域灯光不弱POI密度却不高——大概率是新交付的住宅区或大型工地。反过来某个区域POI密度高但灯光一般可能是传统商圈在夜间经济上还有潜力。这种交叉分析能帮助判断城市发展所处的阶段对宏观研究很有参考价值。写在最后关于这套数据我的几点实际体会这一年用下来我认为2025年版中国分省/分市POI点位数据最大的价值在于它把“全国底图”和“城市细节”很好地对齐了。省级文件做快速浏览和全局统计市级文件做深度分析和业务落地数据的组织方式不折腾人开放心态直接分析就好。不过我也要说句公道话任何POI数据都做不到100%完美。偏远地区的覆盖依然有短缺个别新开业的POI入库需要时间分类口径也可能和某些垂直行业的需求对不上。关键是理解数据的边界在分析时给结论预留合理的容差。最后给一个实在的建议如果你准备以这套数据为基础做长期产品级应用不要只下载一次就完事最好建立每个季度定向更新机制。空间数据的价值随时间衰减极快保持动态更新才是做好应用的长久之道。