
2026年的中国POI点位数据分省/分市我拿到手的第一反应不是看总量而是先把省、市两级目录翻了一遍。POI点位数据说白了就是地图上那些“感兴趣的点”饭店、医院、学校、加油站、写字楼、仓库、公交站……每一个点都带经纬度和属性信息单独看是一个坐标叠加上时间和属性就成了判断线下商业布局、物流网络覆盖或城市规划进度的重要素材。这套数据最核心的卖点是按省、按市切好了你不用自己再做行政区划匹配拿到某个区域就能直接开工。这篇东西不打算给你堆概念重点讲三件事这类数据从哪来、怎么洗、怎么用以及用Java或Python处理时最容易踩的坑。无论你是做商业分析、GIS开发、地产选址还是单纯在搞数据可视化练手把这条链路走通后面很多活儿都能直接复用。1. POI数据到底是个啥从省市级维度看价值1.1 分省分市的数据为什么这么“香”单纯给你一份全国POI数据很多人第一反应是“这有什么可稀罕的”。但分省分市切好之后价值完全不一样。先说最直接的场景连锁品牌做门店选址。你拿全国数据硬筛数据量动辄几千万条光加载就把内存吃满但如果你只需要判断成都市场直接取四川省或者成都市子集几万条到几十万条数据普通笔记本就能跑得动。再说一个我实际遇到过的需求某物流公司要做“次日达”覆盖测算。他们关心的不是全国有多少个网点而是每个地级市辖区内快递柜、驿站、转运中心的密度分布。这种需求如果拿全国数据临时按城市筛选至少要写一堆正则去匹配地址字段但数据源已经按省、市切好直接按文件夹或者表分区读取代码量能砍掉一半还多。分省分市还有一个隐藏优势方便做横向对比。同一个维度在全国范围看是平均值按省、市拆开看就是一张竞争地图。比如餐饮POI密度广东和西藏完全没有可比性但同是长三角的城市苏州和无锡之间就能比出商业中心的辐射差异。这种对比如果不拆到地级市几乎没法落地。1.2 一条POI记录里都装了哪些字段不要以为POI数据就是一个坐标加一个名字。实际上一份能用的POI数据字段设计是有固定套路的。我拆解一下常见的2026年版分省分市POI数据通常包含这么几组字段基础标识POI唯一编号、名称、地址、电话。唯一编号是最容易被忽略的很多人拿到数据先删掉等后面要去重或关联业务数据时才发现麻烦。地理坐标经纬度WGS84或GCJ-02坐标系、所在省、所在市、区县、乡镇/街道。类别信息大类餐饮、购物、医疗、教育等、中类、小类有的还会带品牌标签。运营属性营业状态、营业时间、评分、评论数。这个不是所有数据源都给但给到这个层级的基本都是商业级数据。重点提醒一下坐标系统。国内来源的POI数据经常用GCJ-02火星坐标而GPS设备或国际数据源用WGS84。两者之间有几百米的偏移直接混用会导致点落到错误的路口或建筑上。后文我会专门讲怎么处理。1.3 2026年这版数据跟往年有什么不同从趋势上看2026年的分省分市POI数据有几个变化值得关注。第一是覆盖范围更全乡镇级POI明显增加。前几年很多数据商只覆盖到县城乡镇只有基础政府机构现在随着县域经济被重视乡镇一级的餐饮、零售、物流点位补得很快。第二是动态属性更多营业状态、暂时关闭标记这类字段比例大幅提高这和消费行业经营波动直接相关。第三是数据更新频率从季度更新往月度更新走一些头部门店连锁品牌的数据已经能做到按月同步。这些变化对使用者意味着什么如果你做的是长期趋势研究光看静态点位数量是远远不够的必须结合时间维度看新增和关闭数量。2026年的数据结构里很多厂商已经开始提供“首次出现时间”和“最后确认时间”这类时间戳字段做生命周期分析就方便多了。2. 数据来源怎么选公开、商用还是自采2.1 公开渠道能拿到什么网上能看到不少免费的POI数据大多是爬虫爬出来的快照质量参差不齐。这类数据适合做技术验证或Demo原型不适合直接上生产。免费数据的通病是字段不全很多只有名称、坐标和一级分类拿它做精细分析会发现维度不够用另一个问题是时效性差点位新增和关闭根本更新不到。常用的免费来源主要是几个地图平台的开放接口。它们的优势是覆盖面广、更新快缺点是接口配额有限单次查询有数量上限想拉全一个省的POI得用关键词加网格分页跑很长时间。而且平台对高频抓取有风控账号容易被限制实际操作时要控制请求频率加随机延时最好配多账号轮换。这一块合规性也要注意不要拿接口做超出平台允许范围的商业化使用。2.2 商用数据源的取舍如果你的工作对数据质量有硬要求比如商业选址、投资分析、政府咨询商用数据源基本是绕不开的。市面上主流的数据商提供的2026年分省分市数据单省几十万条、全国几千万条是常态年费从几千到几十万都有差异主要在更新频率、字段维度、售后服务上。选商用源我比较看三点更新频率是否真的按月执行。很多数据商宣传月更但实际是三个月才动一次。坐标系是否标注清楚。有些数据商给的是GCJ-02文档里却全篇不提拿去做空间计算很容易栽跟头。去重和清洗是否做过。大厂的原始数据能干净到什么程度你永远猜不到。建议采购前要求对方拿一个中等城市的完整样例数据自己跑一遍空间校验看看有没有点落在河流、公园或荒地中央。这种检测很简单拿行政边界做空间匹配看落点误差分布就行。2.3 自己采集的边界与成本自采POI数据最常见的形式是派团队到线下扫街或者用移动采集车。这个成本极高不是一般企业能长期玩的。自采数据的优势在于独一无二能拿到竞品永远拿不到的信息比如某个商场每个铺位的真实营业状态某条街每个商户的外摆面积。对做连锁零售的人来说这种差异化数据价值巨大。但自采的坑也很明显。首先是成本一辆采集车一个月的运维费用可以请两个全职数据分析师其次是数据治理即便是线下踩点回来的数据同样面临地址标准化、坐标纠偏、去重合并的一整套流程最后是合规风险连续采集个人信息相关场所的详细数据需要注意边界不能踩到隐私红线。我的判断是普通团队没必要自建采集体系公开数据做原型验证商用数据做业务主数据自采数据只关注核心竞争区域三者结合才是效率最高的方案。3. 数据清洗与标准化拿到手的第一件事3.1 首次洗数据的必修动作不管数据来源是哪家到手的第一件事永远是做基础体检。我通常分四步走。第一步是检查坐标系和范围。导入数据后先对经纬度做一个快速范围判断中国的经纬度大致在东经73度到135度、北纬18度到54度之间超出这个范围的记录直接标记为异常交给后续人工复核。第二步是字段缺失率统计。针对关键字段比如名称、经纬度、省份、城市、类别逐列统计缺失率。缺失率超过5%的字段在分析阶段就要特别小心不能直接拿来做聚合统计。第三步是行政区划匹配。即使数据里已经带了省市区字段也建议用空间边界重新做一遍匹配。因为数据商给行政归属偶尔会出错一条记录标注成A市但坐标实际落在B市如果直接按字段聚合结果会偏差很大。用边界匹配可以纠正大部分这类错误。第四步是时间戳标注。如果原始数据里有数据快照时间要保留下来如果没有也要在内部表里加上“入库时间”方便后续做增量更新和版本回溯。这步很多人不做等三个月后数据更新了才发现新旧混淆到时候哭都来不及。3.2 去重算法GeoHash加距离判断POI数据最头疼的问题就是重复。同一家店在地图平台上可能被录入两三条记录一条叫“老王牛肉面”一条叫“老王牛肉面总店”还有一条电话和地址都一样但名称略有差别。单纯的名称去重不可靠坐标去重也不可靠因为不同采集批次坐标本来就会有偏移。业界通用的做法是GeoHash加距离阈值双重判断。GeoHash是把经纬度编码成一个字符串精度可以通过字符串长度控制。比如使用7位GeoHash覆盖范围大约是几十米到上百米适合判断相距很远的点再用精确距离进一步确认。import pandas as pd import numpy as np from math import radians, sin, cos, asin, sqrt def haversine(lon1, lat1, lon2, lat2): R 6371000 dlon radians(lon2 - lon1) dlat radians(lat2 - lat1) a sin(dlat/2)**2 cos(radians(lat1)) * cos(radians(lat2)) * sin(dlon/2)**2 return 2 * R * asin(sqrt(a)) # 示例找出距离在100米内的重复点 # 先按GeoHash粗分组再在组内做距离计算 df[geohash] df.apply(lambda row: encode_geohash(row[lng], row[lat], precision7), axis1) grouped df.groupby(geohash)实际业务里我建议把阈值设在50到100米之间。太小的阈值会导致同店不同门头的记录漏掉太大又容易把同一条街上紧挨着的两家店误判成重复。这个阈值没有固定值取决于你业务对误判和漏判的容忍度。餐饮行业我通常用60米商场内部品牌店除外因为同楼层不同店铺距离可能就十米甚至更近需要结合类别和名称综合判断。3.3 地址与类别字段的标准化地址字段是最让人头大的同一个“北京市朝阳区建国路88号”不同批次可能写成“建国路88号”“朝阳区建国路88号”“北京朝阳区建国路88号院”。做标准化时我会先拆分省市县区字段再拆分详细地址然后按“行政区划道路门牌号”的结构做归一化。这一步用现成的地址解析工具能省不少事但要注意解析错误的积累批量处理后一定要抽检。类别字段的标准化同样重要。不同数据源的分类体系差异很大有的用“餐饮服务”有的用“美食”还有的直接用平台类目标签。建议第一步先映射成统一的“大类-中类-小类”三级体系。大类控制在一级业务维度比如吃、住、行、游、购、娱中类控制在10到20个小类尽可能保留原始标签方便后续细分分析。标准化的意义在做跨区对比时体现得最明显。如果你不统一类别成都市用A分类体系、重庆市用B分类体系两个城市的“零售POI密度”就完全没有可比性。我见过很多分析报告数据都是好数据就死在分类口径不一致上。4. 实操环节用Python处理分省分市POI数据4.1 准备一份趁手的目录结构我处理这类项目的习惯是先按“省市-数据版本-日期”搭目录。比如这样/data_2026/ /province/广东省/ 深圳_202601.xlsx 广州_202601.xlsx /province/四川省/ 成都_202601.xlsx /merged/ 全国_202601_清洗后.parquet好处是每个城市的原始文件独立存放处理脚本只负责读取不覆盖源文件防止误操作。中间文件统一放merged目录最终结果单独放output目录。这样哪怕清洗逻辑出Bug重新跑一遍也不会污染原始资料。这个习惯帮我挽回了好几次局面。4.2 数据加载与基础清洗脚本以最常见的Excel文件为例用pandas读取后先做基础字段裁剪和类型转换。不要把全部字段一锅端进来留业务要的字段就行内存占用会小很多。import pandas as pd df pd.read_excel(data_2026/province/广东省/深圳_202601.xlsx, dtype{poi_id: str}) cols [poi_id, name, lng, lat, province, city, district, category, sub_category, status] df df[[c for c in cols if c in df.columns]] df[lng] pd.to_numeric(df[lng], errorscoerce) df[lat] pd.to_numeric(df[lat], errorscoerce) df df.dropna(subset[lng, lat]) # 用边界框过滤明显异常坐标 china_bbox (73, 18, 135, 54) df df[(df[lng] china_bbox[0]) (df[lng] china_bbox[2]) (df[lat] china_bbox[1]) (df[lat] china_bbox[3])]几点提醒poi_id一定要读成字符串不然Excel里超过15位的数字会被科学计数法截断精度直接丢经纬度字段用errorscoerce解析不了的就置空然后统一过滤比后面计算时报错要舒服得多。再就是读Excel时如果文件很大建议把参数engine换成openpyxl配合read_only模式能减少很多内存压力。4.3 按省、市维度做聚合统计清洗完之后最常见的需求就是统计每个省、每个市的POI数量、类别分布、行业密度。城市级别的聚合用groupby就能搞定。city_stats df.groupby([province, city]).size().reset_index(namepoi_count) cat_city df.groupby([province, city, category]).size().reset_index(namecnt) pivot cat_city.pivot_table(index[province, city], columnscategory, valuescnt, fill_value0)如果要做空间密度分析这时就应该引入GeoPandas。按区县聚合并计算每平方公里的POI密度这是选址和城市分析的标配。import geopandas as gpd gdf gpd.GeoDataFrame(df, geometrygpd.points_from_xy(df[lng], df[lat]), crsEPSG:4326) # 叠加到区县边界做空间连接 county gpd.read_file(data_2026/boundary/区县边界.shp) joined gpd.sjoin(gdf, county, howleft, predicatewithin) density joined.groupby(区县名).size() / joined.groupby(区县名)[面积_km2].first()空间连接这一步会让数据量大的时候计算变慢建议先把全国数据拆到省份按省跑完再concat。我是吃过这个亏的几百万个点直接空间连接跑了快俩小时没出结果拆分后十分钟就完事。4.4 结果导出与后续可视化分析完建议直接把结果落到parquet文件和Excel两种格式。parquet保留全字段给你下次做更复杂分析用Excel给业务同事和领导看。写Excel时用to_excel加sheet_name划分模块一个文件里放多个Sheet比一个Sheet塞一堆列直观得多。with pd.ExcelWriter(output/省市POI统计_202601.xlsx, engineopenpyxl) as writer: city_stats.to_excel(writer, sheet_name省市总量, indexFalse) pivot.to_excel(writer, sheet_name类别分布, indexTrue) density.to_excel(writer, sheet_name区县密度, indexTrue)可视化层面稍微提一句不要一上来就画全国地图热力图那种图信息量太大根本看不出细节。先按省圈一批重点城市逐个画城市内部的POI核密度分布有对比、有层次才真正对业务有指导作用。5. 用Excel处理POI数据时绕不开的Apache POI问题5.1 为什么专门聊Apache POI看到这里你可能疑惑不是聊POI点位数据吗怎么扯到Apache POI去了其实搜索引擎里“apache poi”这个词和“poi数据集”经常一起出现原因很简单大量POI数据分发和交换都依赖Excel文件而后端Java系统读写Excel最常用的库就是Apache POI。尤其在企业环境里Java服务接收数据商交付的.xlsx文件、写统计报表、生成带嵌入样式的结果文档全是Apache POI的活。这中间有两个问题出现频率最高一个是老版本Apache POI存在安全漏洞另一个是用POI写Word表格时单元格宽度怎么设置都不生效。这俩坑我都踩过写出来希望对你有用。5.2 XSSFExportToXML的XXE漏洞原理与修复先说漏洞。Apache POI 4.1.0及更早版本的XSSFExportToXML接口存在XML外部实体注入风险。XSSFExportToXML的作用是把工作表内容导出成XML格式但在处理XML外部实体时不够严谨攻击者可以构造一个包含外部实体引用的XML文件解析时读取服务器上的本地文件或者发起内网请求造成信息泄露。听起来有点抽象我解释得直白一点如果你有一个Java服务接收用户上传的.xlsx文件内部用XSSFExportToXML把数据转成XML再往下游处理那攻击者可以精心构造一个Excel文件里面藏一段恶意XML服务端一解析服务器里的某个配置文件内容就可能被当成本地实体展开写到导出结果里。更严重的还能做SSRF探测内网服务。修复方案很简单升级到Apache POI 4.1.1或更高版本。如果项目暂时不能升级要马上在代码里禁止解析外部实体。以DocumentBuilderFactory为例最稳妥的方式是禁掉DOCTYPE声明DocumentBuilderFactory dbf DocumentBuilderFactory.newInstance(); dbf.setFeature(http://apache.org/xml/features/disallow-doctype-decl, true); dbf.setFeature(http://xml.org/sax/features/external-general-entities, false); dbf.setFeature(http://xml.org/sax/features/external-parameter-entities, false); dbf.setXIncludeAware(false); dbf.setExpandEntityReferences(false);这三个Features组合起来能基本把XXE路径堵死。顺便说一下线上如果存在大量历史文件需要解析又没法升级框架可以在网关或文件接收层加一道过滤检查上传文件里是否包含!DOCTYPE或!ENTITY字符串直接拦截会更省事。5.3 用POI设置Word表格单元格宽度另一个高频坑是用Apache POI生成Word报告时表格单元格宽度设了没反应。典型场景是你把各省市POI统计表导出成Word文档发给业务方想控制某列宽度让表格排版整齐结果调用XWPFTableCell.setWidth()后打开Word发现宽度根本没变。原因是纯用高层API设置宽度常常无效真正控制单元格宽度的是底层XML里的tcW元素需要用底层CT类直接操作。import org.apache.poi.xwpf.usermodel.*; import org.openxmlformats.schemas.wordprocessingml.x2006.main.*; public class TableCellWidthUtil { public static void setCellWidth(XWPFTableCell cell, int widthTwips) { CTTcPr tcPr cell.getCTTc().isSetTcPr() ? cell.getCTTc().getTcPr() : cell.getCTTc().addNewTcPr(); CTTcW tcW tcPr.isSetTcW() ? tcPr.getTcW() : tcPr.addNewTcW(); tcW.setType(STTblWidth.DXA); tcW.setW(java.math.BigInteger.valueOf(widthTwips)); } }这里单位是twip1英寸等于1440 twips1厘米约等于567 twips。比如你想把第一列设为4厘米直接传2270左右即可。还有一点设置单元格宽度之前建议先把整张表格的表格级宽度布局方式改成STTblLayoutType.FIXED不然Word会按内容自动调整列宽你的手工设置照样被覆盖。CTTblPr tblPr table.getCTTbl().getTblPr(); if (tblPr null) { tblPr table.getCTTbl().addNewTblPr(); } tblPr.addNewTblLayout().setType(STTblLayoutType.FIXED);5.4 用POI处理超大Excel数据时的内存优化最后补一个处理大文件时的老规矩POI的XSSFWorkbook会一次性把整个工作簿读进内存几万条POI数据的统计报表可能没事但如果工作簿里有几十万行内存很容易被撑爆。读取模式用try (InputStream is new FileInputStream(poi_data_2026.xlsx)) { Workbook wb StreamingReader.builder() .rowCacheSize(100) .bufferSize(4096) .open(is); }这里其实用的不是原生POI是com.monitorjbl:poi-streaming这个库底层基于SAX事件模型逐行读取内存占用能降一个数量级。如果是写大量数据直接用原生POI的SXSSFWorkbook开启窗口模式及时把旧数据刷到磁盘。这是我在处理全国范围POI数据生成Excel时最常用的方案。6. 常见问题快查表与避坑心得6.1 常见问题速查表下面这张表是我这几年在处理省市POI数据过程中遇到频率最高的几个问题直接抄作业就行。现象可能原因解决办法聚合后的城市数量与官方数量不符坐标落在边界行政区划字段被标错用省市区边界做空间匹配覆盖原字段同一街区POI数量翻倍数据源重复率高未做去重使用GeoHash加60米阈值去重POI点落偏到隔壁道路坐标系混用GCJ-02与WGS84先确认坐标系再统一做坐标转换Java解析xlsx报Zip bomb文件实际压缩比异常高或确实过大调大ZipSecureFile.setMinInflateRatio或直接换流式读取Word表格单元格宽度设了没生效表格布局是自动模式设置表格布局为FIXED并用CTTcW写宽度解析Excel时服务器内存飙高XSSFWorkbook全量加载改用流式读入或SXSSFWorkbook写出导出的Excel中文乱码字符集设置不对明确使用UTF-8避免平台默认编码6.2 我踩过的几个坑和现在的处理习惯第一个坑是坐标系统一。早期我拿过一份四川的数据文件名写着WGS84实际用的是GCJ-02我拿它跟GPS轨迹去做匹配结果每个点都偏移了四五百米整整调了半天才发现是坐标基准问题。现在我的习惯是任何数据入库前先随机抽几十个点叠加到在线地图上肉眼检查这一招比信任何文档都靠谱。第二个坑是GeoHash去重的误杀。有几家商场紧挨着中间距离就几十米用7位GeoHash粗排后距离计算结果把两家店当成一家删掉。后来处理连锁品牌数据时我先按名称做一次精确匹配再做GeoHash距离去重并且把类别字段纳入去重条件只在同大类内部判断误杀率一下就降下来了。第三个坑是直接把Excel当成数据库用。前期有些中间结果我图省事一直用Excel存每次清洗重新跑一次全链路直到有一次把原始数据和中间结果混在一个目录下脚本读取时串了文件浪费了两天才补回数据。从那以后我坚持把原始数据、中间数据、结果数据分目录管理原始文件改成只读属性脚本里也写了绝对路径白名单防止手滑覆盖。做省市级POI数据分析真正难的不是算法有多复杂而是数据治理习惯有多规范。拿到的数据先做体检坐标统一、去重、字段标准化这三个动作做到位后面80%的分析需求都能顺畅跑通。如果你正准备拿一套2026年的分省分市POI数据做项目把这篇文章提到的检查流程过一遍至少能帮你少走一个月弯路。最后再分享一个小技巧无论你用的是Python还是Java处理POI数据时都建议把坐标精度保留到六位小数以上不要因为嫌数字长就四舍五入。经度纬度小数点后第六位对应约0.11米的精度一旦四舍五入到四位点位可能就漂移了十几米这对判断一个点到底在哪栋建筑、哪个商铺影响是非常大的。数据精度这个东西越是到省市细分之后越能拉开差距。