
Python 数据分析与可视化:手把手教你制作地理热力图
上周有个朋友问我,说他手里有一份全国门店销售数据,想做成那种能看到区域热度的地图可视化,问我该用什么工具。我当时就想,这问题问得好啊,地理热力图确实是数据分析展示的一把利器,但很多人对具体操作流程并不清楚。今天我就把用 Python 制作地理热力图的完整方法分享出来,内容比较实用,感兴趣的朋友可以跟着一步步试试。
什么是地理热力图
在说具体操作之前,先简单解释下什么是地理热力图。热力图大家可能都见过,就是用颜色深浅来表示数据密度或强度的一种可视化方式。地理热力图呢,就是把这种概念绑定到了真实的地理坐标上。
举个例子来说,假设你有一个奶茶店在全国的销量数据,普通表格看起来很枯燥,但做成地理热力图之后,你就能直观地看到哪些城市、哪些区域销量最高,颜色越深代表数据越集中。这种展示方式不仅自己分析起来方便,拿给领导汇报或者做演示时也更容易让人抓住重点。
地理热力图的应用场景非常广泛。除了商业销售分析,还有疫情防控中的人口流动监测、房产价格分布可视化、交通拥堵情况展示、气象数据呈现等等。可以说只要你的数据包含地理位置信息,且想要直观展示分布规律,地理热力图都是值得考虑的选择。
为什么选择 Python 来制作
市场上做地图可视化的工具其实挺多的,Excel 有插件能做一些基础的,商业软件像 Tableau、PowerBI 功能也很强大。但为什么我特别推荐用 Python 来做这个呢?
首先 Python 的生态太丰富了。专门做地理数据处理的库一抓一大把,而且大部分都是开源免费的。你用 Python 处理完数据可以直接生成交互式网页地图,别人打开就能随意缩放、点击查看详细信息,这种交互体验是静态图片给不了的。

其次是灵活性高。如果你的数据需要进行复杂的清洗、转换、统计,Python 的 pandas 配合各种地理库可以一条龙完成。从原始数据到最终可视化,中间所有步骤都能用代码记录下来,下次有类似需求时改改参数就能复用,省时省力。
还有一点很实际,就是性价比高。Python 本身免费,各种地理可视化库也免费,不像某些商业软件那样需要付费订阅。对于个人学习或者中小企业来说,这个优势还是很香的。
核心工具库介绍
用 Python 做地理热力图,有几个库是一定要了解的。我先简单介绍它们的特点和适用场景,这样你后面动手时就能根据需求选择合适的工具组合。
Folium:交互式地图的首选
Folium 是我平时用得最多的一个库,它基于 JavaScript 的 Leaflet 地图框架,但用 Python 来调用。最大的优点是生成的地图是 HTML 文件,可以直接在浏览器中打开,支持缩放、拖动、点击弹出详细信息等功能。
Folium 做热力图特别简单,核心函数就那几个,传入经纬度坐标和对应的数值,它自动给你生成漂亮的渐变色热力图。而且它自带多种地图底图可选,默认的是 OpenStreetMap 的街道图,你也可以换成深色主题或者卫星图风格。
Geopandas:处理地理数据的利器
如果你的数据本身是 Shapefile 格式,或者需要和行政区划边界结合,Geopandas 就是必备工具了。它扩展了 pandas 的数据结构,添加了 GeoSeries 和 GeoDataFrame 类型,专门处理矢量地理数据。

Geopandas 背后对接了 GEOS 和 PROJ 等专业地理计算库,支持投影转换、空间连接、缓冲区分析等高级操作。简单说,如果你需要把销售数据和某个城市的行政区划绑定,或者要计算点到边界的距离,Geopandas 都能搞定。
Plotly:专业级可视化
Plotly 是做数据可视化的大杀器,它的地理图表功能非常强大。做散点地图、填充地图、密度图都不在话下,而且生成的图表可以嵌入 Jupyter Notebook 或者导出为 HTML。
Plotly 的优势在于图表颜值高、交互做得好,而且有完善的 API 文档。特别是它的 density_mapbox 函数,做热力图效果很惊艳,配合 Mapbox 的底图看起来非常专业。
其他辅助库
除了上面三个主力库,还有一些库经常配合使用。Matplotlib 和 Seaborn 做静态地图绑定数据的时候经常用到,特别是需要把地图嵌入到论文或报告里时。Basemap 是 Matplotlib 的地理扩展库,虽然现在慢慢被 Cartopy 取代,但很多老项目还在用。JSON 格式的地理数据可以用 GeoJSON 库来读取和处理。
数据准备工作
很多人以为做地图可视化最难的是画图,其实不然,数据准备才是真正花时间的环节。原始数据往往存在各种问题:格式不统一、坐标缺失、地理位置描述不规范等等,这些都需要在画图之前解决掉。
数据格式要求
地理热力图需要的数据其实不复杂,核心就是两部分:地理位置信息和数值信息。地理位置可以用不同的形式表示,最常见的是经纬度坐标、经度加纬度各一列。其次是用地址字符串,比如"北京市朝阳区某某路",这种情况下需要通过地理编码服务把文字转换成坐标。
还有一种是用行政区划代码,比如中国的县区级行政区划代码是 6 位数字,这种情况下你需要一个行政区划边界文件来匹配。数值信息就是你想用颜色深浅来表达的那个指标,可以是销售额、用户数、点击量等等数值型数据。
常见数据清洗操作
拿到数据后,首先检查经纬度字段有没有缺失值。缺失不多的话可以用周边城市或区域的平均值填充,缺失太多就干脆删掉吧,不然会影响可视化效果。
然后要检查坐标是否在合理范围内。中国的经度范围大致在 73 到 135 度之间,纬度在 3 到 54 度之间。如果有坐标超出这个范围,要么是输错了,要么是经纬度写反了,这种情况需要修正。
如果原始数据只有地址文字,没有坐标,那就需要做地理编码。Python 里有 geopy 库可以调用各大地图服务的 API 来获取坐标。不过要注意,大部分地图 API 都有调用次数限制,免费额度用完后需要付费。
实战:制作一份销售热力图
理论说得差不多了,接下来我用一个具体例子来说明完整的操作流程。假设我们有一份模拟的门店销售数据,包含门店名称、城市、经度、纬度、月销售额这几个字段。
第一步:导入必要的库
import pandas as pd
import folium
from folium.plugins import HeatMap
这里我们用 pandas 处理数据,用 folium 画热力图。HeatMap 是 folium 的一个插件,专门用于生成热力图层。
第二步:读取和预览数据
df = pd.read_csv('sales_data.csv')
print(df.head())
print(df.info())
这一步主要是确认数据读取没问题,看看字段类型对不对,有没有缺失值。如果数据量不大,print 出来检查一遍比较放心。
第三步:数据清洗
删除含有缺失经纬度或销售额的行,这部分数据无法参与可视化。检查坐标范围是否在中国境内,如果有异常值需要修正或者删除。
df_clean = df.dropna(subset=['longitude', 'latitude', 'sales'])
df_clean = df_clean[(df_clean['longitude'] > 73) & (df_clean['longitude'] < 136)]
df_clean = df_clean[(df_clean['latitude'] > 3) & (df_clean['latitude'] < 54)]
这里做了一个简单的边界过滤,把明显超出中国范围的坐标剔除了。实际项目中可能还需要更精细的处理,比如检查经纬度组合是否在陆地上(避免出现海里)。
第四步:准备热力图数据格式
Folium 的 HeatMap 函数需要一个列表格式的输入,每个元素是 [纬度, 经度, 权重] 这样的结构。权重就是你想用颜色深浅表达的那个数值。
heat_data = df_clean[['latitude', 'longitude', 'sales']].values.tolist()
这里直接把三列提取出来转成列表,顺序不能乱,必须是纬度在前、经度在后。我第一次用的时候就搞反过,结果地图显示的位置完全不对。
第五步:创建地图对象
map = folium.Map(location=[35, 105], zoom_start=4, tiles='OpenStreetMap')
location 参数设置的是地图中心的经纬度,中国地图大概选 [35, 105] 这个位置比较居中。zoom_start 是初始缩放级别,4 差不多是全国视图。tiles 参数选择底图风格,OpenStreetMap 是默认的街道图,也可以换成 'CartoDB positron' 那种简洁的浅色底图。
第六步:添加热力图层
HeatMap(heat_data, radius=15, blur=10, max_zoom=13).add_to(map)
这三个参数需要解释一下。radius 是每个数据点的半径大小,值越大热力图越扩散。blur 是模糊程度,值越大热点越模糊、过渡越平滑。max_zoom 是在最大缩放级别时热力图的显示方式。
这些参数没有标准答案,要根据你的数据分布和想要的效果来调整。如果数据点比较密集,radius 可以设小一点;如果数据分散,想突出重点区域,radius 可以设大一些让热点更明显。
第七步:保存和查看
map.save('sales_heatmap.html')
这句代码把生成的地图保存为 HTML 文件,直接用浏览器打开就能看到交互式热力图了。可以拖动、缩放,点击任意位置能看到详细信息。如果需要嵌入到网页里,直接把这个 HTML 文件嵌入即可。
进阶技巧和注意事项
掌握了基础做法之后,还有一些进阶技巧可以让你的热力图更专业、更有说服力。
多图层叠加
有时候你需要在同一张地图上展示多种信息。比如门店位置用标记点表示,销量用热力图表示,配送范围用圆圈表示。Folium 支持多层叠加,只要创建不同的图层对象 add 到同一个地图上就行。
folium.Marker([lat, lon], popup='门店A').add_to(map)
folium.Circle([lat, lon], radius=5000).add_to(map)
这样做出来的地图信息更丰富,看的人能同时获取多个维度的信息。不过也不要叠加太多层,不然会显得杂乱,反而影响阅读。
配色方案选择
热力图的配色很重要,不同的配色传达的情绪完全不一样。红色系代表热度高、密集,蓝色系代表冷门、分散。Folium 默认的配色是红黄蓝渐变,你也可以自定义颜色阶梯。
如果你的数据反映的是积极指标(如销售额、用户量),建议用暖色调;如果反映的是消极指标(如投诉量、故障率),可以用冷色调或者直接反转色阶。
投影和坐标系
这一点经常被忽略,但专业做地理数据的都会注意到。中国常用的坐标系有 WGS84(经纬度坐标)、GCJ02(火星坐标,高德地图用的)、BD09(百度坐标)。不同来源的坐标可能属于不同坐标系,直接混用会导致位置偏移。
如果你的数据来源复杂,可能需要做坐标系转换。Python 里有 pyproj 库可以做坐标转换,或者直接用在线转换工具也可以。
大数据量优化
如果数据点超过一万个,Folium 的热力图可能会变得卡顿。这时候可以考虑几种优化方案:一是做数据聚合,把相近的多个点合并成一个点;二是使用热力图聚合功能,Folium 自带的 HeatMapWithTime 或者 WebGL 版本的插件对大数据量支持更好;三是考虑后端渲染,用 GeoServer 或者 Mapbox 这种专业地图服务来处理。
常见问题排查
我整理了几个自己踩过的坑和朋友们经常遇到的问题,供大家参考。
地图加载出来是空的,完全没有热力点。这种情况通常是数据格式不对,检查一下列表顺序是不是 [纬度, 经度, 数值],而不是 [经度, 纬度, 数值]。另外也可能是数值列里有非数字字符,导致解析失败。
热力点位置明显不对,跑到海里或者国外去了。首先检查经纬度有没有写反,然后检查坐标是不是在你指定的坐标系下。中国特色的问题是很多国内地图服务用的是 GCJ02 坐标系,而国际通用的 GPS 数据是 WGS84 坐标系,两者之间有几百米的偏差。
生成的 HTML 文件很大,打开很慢。如果原始数据量很大,HeatMap 生成的 HTML 包含所有数据点信息,文件体积自然就大。可以考虑在保存之前做数据采样,只保留有代表性的点,或者开启 HTML 文件的压缩选项。
小结一下
用 Python 制作地理热力图的流程基本就是这些:准备数据、选择工具、调整参数、生成地图。看起来步骤不多,但每个环节都有讲究,数据质量决定最终效果,参数调优影响视觉呈现。
如果你正在处理类似的地理数据可视化需求,不妨从今天介绍的方法入手试试。Python 的学习曲线不算陡峭,网上各种资源也很多,遇到问题多搜一搜基本都能找到解决方案。
对了,如果你在数据分析过程中还需要其他辅助,Raccoon - AI 智能助手可以提供一些参考建议。无论是工具选择、方法论还是具体实现思路,都可以聊聊。数据分析这条路大家一起交流进步,才更有意思。




















