新冠数据集时空可视化实战:从坐标匹配到pyecharts地图

发布时间:2026/10/14 15:30:57
新冠数据集时空可视化实战:从坐标匹配到pyecharts地图
简介这份资源面向数据分析初学者、地理可视化爱好者及公共卫生数据研究者提供一套可直接上手的新冠疫情数据集合用于练习地图绘制、城市定位与疫情趋势分析。压缩包共3个文件包含2个csv与1个json整体约360KB体积轻便易于加载。其中json文件提供地理边界数据可用于绘制全国或省级地图轮廓一个csv记录全国城市经纬度坐标便于将疫情数据精准落点到具体城市另一个csv为2020年2月9日中国新冠病毒疫情统计涵盖各省市确诊、疑似、治愈与死亡等字段适合做时间切片分析。目前已有4703人学习下载说明该数据集在同类练习中认可度较高。借助这套数据读者可完成从数据清洗、坐标匹配到地图渲染的完整流程快速搭建疫情分布可视化小项目也可用于课程作业或数据新闻练习。1. 流调与空间分析的数据底座这份新冠数据集到底能跑什么做疫情时空可视化的人大概都经历过这种尴尬地图底图有了确诊数字也有了但要把“哪一天、哪个城市、涨了多少”对齐到一张图上中间缺的恰恰是那份能直接喂给 pandas 的干净表格。这份新冠病毒数据集就是冲着这个缺口来的它把地理位置、全国城市坐标、以及 2020 年 2 月 9 日前后那批公开疫情统计揉在一起省掉了从零爬取和清洗的功夫。适合谁用做课程设计的学生、需要快速搭一个时空热力图原型的开发者、以及想拿真实数据练手 Python 数据分析的从业者。它不承诺预测精度也不替代官方口径但作为一份结构化的历史切片足够你把“数据加载—坐标匹配—时间序列聚合—地图渲染”这条链路完整跑通一遍。下面我按实际拆包和跑通的顺序把这份资源怎么用、参数怎么设、哪里容易翻车讲清楚。2. 拆开数据包三张表的结构与字段含义2.1 地理位置表与全国城市坐标表的分工拿到压缩包先别急着写代码用ls或资源管理器看一眼文件构成。通常这类数据集会拆成两个维度的地理信息一张是省级或市级的地理位置表记录行政区名称和对应的经纬度中心点另一张是全国城市位置表粒度更细覆盖到地级市甚至区县字段一般包含城市名、省份、经度、纬度。这两张表的关系是“一对多”——一个省对应多个城市匹配时靠省份名或城市名做键。常见做法是先用城市坐标表做主表再把疫情统计按城市名 join 进去这样地图上每个点都有坐标可落。字段命名上要留个心眼有的版本用province/city有的用中文省份/城市还有的混用拼音。加载后第一件事是df.columns打印一遍别默认列名。经纬度字段常见叫lng/lat或longitude/latitude单位是十进制度直接给 pyecharts 或 folium 用没问题。2.2 2020-2-9 疫情数据表的字段与时间口径2020 年 2 月 9 日这个时间点选得有意思——正好是那波全国性统计口径调整前后的节点数据里往往同时有累计确诊、新增确诊、疑似、死亡、治愈几列。字段名可能是confirmed/suspected/dead/cured也可能是中文。关键是要确认这版数据是“截至当日累计”还是“当日新增”两者在画时间序列时曲线形态完全不同。我的习惯是先看数值量级累计确诊到 2 月 9 日全国应该是在几万这个量级如果某城市数值只有个位数那大概率是新增而非累计。时间字段如果是字符串格式可能是2020-02-09或2020/2/9统一用pd.to_datetime转一下避免后面按日期分组时排序错乱。2.3 用 pandas 做一次结构体检正式分析前跑一段体检代码把行数、列名、缺失值、重复项一次性看清楚。这一步花两分钟能省掉后面半小时的 debug。import pandas as pd # 按实际文件名替换注意编码中文列名常见 utf-8 或 gbk city_coord pd.read_csv(全国城市位置.csv, encodingutf-8) covid pd.read_csv(2020-2-9疫情数据.csv, encodingutf-8) # 结构体检形状、列名、缺失、重复 for name, df in [(城市坐标, city_coord), (疫情数据, covid)]: print(f {name} ) print(形状:, df.shape) print(列名:, df.columns.tolist()) print(缺失值:\n, df.isnull().sum()) print(重复行:, df.duplicated().sum())逻辑说明shape告诉你数据规模列名决定后续用哪个键做 mergeisnull().sum()定位哪些城市缺坐标或缺确诊数duplicated().sum()排查是否有重复录入。参数上encoding如果报UnicodeDecodeError换成gbk或gb18030再试这是中文 CSV 最常见的翻车点。3. 从坐标到地图匹配、聚合与可视化落地3.1 城市名匹配的三种对齐策略数据能不能用八成卡在“名字对不上”。疫情表里写“武汉市”坐标表里写“武汉”或者一个带“市”一个不带直接 merge 就是一堆 NaN。我一般按优先级试三种策略第一精确匹配两边都去掉“市”“区”“县”后缀再 join第二用省份城市双键匹配降低重名干扰第三对实在对不上的做手工映射字典兜底。# 策略一去掉常见行政后缀后匹配 def clean_name(s): if pd.isna(s): return s for suffix in [市, 区, 县, 自治州, 地区]: s s.replace(suffix, ) return s.strip() city_coord[city_clean] city_coord[城市].apply(clean_name) covid[city_clean] covid[城市].apply(clean_name) merged pd.merge(covid, city_coord, oncity_clean, howleft) # 检查匹配率低于 90% 就要回头看名字 match_rate merged[经度].notna().mean() print(f坐标匹配率: {match_rate:.2%})逻辑说明clean_name把行政后缀统一剥掉让“武汉市”和“武汉”能对上。howleft保证疫情数据一行不丢匹配不上的经度为 NaN方便你统计匹配率。参数上后缀列表按你数据里实际出现的调整别照抄。匹配率低于九成说明还有别名没覆盖比如“襄樊”和“襄阳”这种历史改名得手工补映射。3.2 按省份聚合与时间序列透视单日数据只能画一张静态图要做趋势就得把多天数据摞起来。如果资源里只有 2 月 9 日一天那至少可以按省份做横向对比如果还带了其他日期就能透视成“日期 × 省份”的矩阵。# 按省份聚合累计确诊 province_stat merged.groupby(省份).agg( 确诊总数(确诊, sum), 城市数(城市, nunique) ).reset_index().sort_values(确诊总数, ascendingFalse) # 如果有多个日期透视成时间序列 # pivot merged.pivot_table(index日期, columns省份, # values确诊, aggfuncsum)逻辑说明groupby(省份)把城市级数据汇总到省级agg里同时算确诊总数和覆盖城市数后者能帮你判断某个省的数据是全量还是抽样。sort_values降序排列方便直接看头部省份。参数上aggfuncsum适用于累计值如果字段是新增确诊求和前要先确认没有重复日期。3.3 用 pyecharts 出一张可交互地图静态图用 matplotlib 也行但做疫情空间分布pyecharts 的 Map 或 Geo 更直观鼠标悬停能看具体数值。from pyecharts.charts import Map from pyecharts import options as opts data_pair [(row[省份], int(row[确诊总数])) for _, row in province_stat.iterrows()] map_chart ( Map() .add(累计确诊, data_pair, china) .set_global_opts( title_optsopts.TitleOpts(title2020-2-9 全国疫情分布), visualmap_optsopts.VisualMapOpts(max_province_stat[确诊总数].max()) ) ) map_chart.render(covid_map.html)逻辑说明data_pair把省份和数值转成 pyecharts 要的元组列表add的第三个参数china指定中国地图底图。VisualMapOpts的max_控制颜色映射上限设成最大值能让色阶拉满对比更明显。渲染出的 HTML 直接用浏览器打开不需要额外服务。注意省份名要和 pyecharts 内置地图的名称一致比如“内蒙古”不能写成“内蒙古自治区”否则该省不显示——这是最常见的玄学问题。4. 避坑与排查这份数据集最容易翻车的五个地方4.1 中文编码报错读一半就崩现象pd.read_csv抛UnicodeDecodeError: utf-8 codec cant decode byte...。 原因文件是 GBK 或 GB18030 编码尤其 Windows 下导出的 CSV。 解决先试encodinggbk再试gb18030还不行就用chardet探测。别用errorsignore硬吞会丢字导致城市名残缺。4.2 城市名对不上地图一片空白现象merge 后大量经度为 NaN地图上只有零星几个点。 原因疫情表和坐标表的城市名写法不一致带不带“市”、简称全称混用。 解决按 3.1 的清洗策略统一去后缀再统计匹配率对历史改名城市如襄樊→襄阳建手工映射字典。匹配率没到九成别急着画图。4.3 累计值和新增值混用曲线形态诡异现象时间序列图忽高忽低或者总量对不上官方口径。 原因没确认字段是累计还是新增把新增当累计求和了。 解决先看单日全国总量量级累计到 2 月 9 日应是万级再检查同一省份多天数据是否单调不减累计值必须单调新增值可以波动。4.4 经纬度顺序颠倒点跑到国外去了现象地图上的点全挤在非洲西海岸或印度洋。 原因把lat当lng用了经纬度写反。 解决中国范围经度约 73–135纬度约 3–53加载后先df[[经度,纬度]].describe()看一眼范围超出这个区间的就是反了交换列名即可。4.5 重复行导致总数虚高现象某省确诊数比官方公布的高出一截。 原因数据里同一城市同一天有多条记录或者 merge 时坐标表有重复城市导致行数膨胀。 解决merge 前对坐标表按城市去重drop_duplicates(subsetcity_clean)merge 后再查一次duplicated().sum()有重复就按业务键去重。5. 进阶玩法把单日切片扩成时空动画与校验闭环单日数据画一张图只是起点。如果你手里这份资源还带了其他日期或者你能从公开渠道补齐相邻几天的切片就能做时间轴动画。pyecharts 的Timeline组件可以把多天的 Map 串起来播放效果比静态图有说服力得多。from pyecharts.charts import Map, Timeline timeline Timeline() # 假设 merged 里有“日期”列按日期分组逐帧添加 for date, group in merged.groupby(日期): stat group.groupby(省份)[确诊].sum().reset_index() pair [(r[省份], int(r[确诊])) for _, r in stat.iterrows()] frame ( Map() .add(累计确诊, pair, china) .set_global_opts( visualmap_optsopts.VisualMapOpts( max_merged.groupby(日期)[确诊].sum().max() ) ) ) timeline.add(frame, time_pointstr(date)) timeline.render(covid_timeline.html)逻辑说明groupby(日期)把数据切成一天一帧每帧单独聚合并生成一个 Map 对象timeline.add的第二个参数是时间轴上的标签。关键参数是VisualMapOpts的max_——必须用全局最大值而不是每帧自己的最大值否则不同日期的颜色没有可比性播放时会看到颜色跳变这是做时间轴动画最容易忽略的细节。再进一步可以给自己搭一个校验闭环把聚合后的省级总数和公开的官方口径做一次比对差异超过阈值就回头查是匹配漏了还是字段理解错了。我一般会写一个简单的断言函数把预期范围和实际值都打出来跑通一次之后后面换数据源也能复用这套检查。def sanity_check(df, province_col, value_col, expected_range): total df[value_col].sum() low, high expected_range status 通过 if low total high else 异常需排查 print(f全国合计: {total}预期区间: [{low}, {high}]校验: {status}) # 累计确诊到 2 月 9 日大致在几万量级按你数据实际口径调整区间 sanity_check(province_stat, 省份, 确诊总数, (30000, 60000))这套习惯是从一次翻车里留下来的当时没做量级校验直接把一份字段理解错的数据画进了汇报图直到有人问“为什么总数比公布的多一倍”才发现是重复行没去。从那以后我每次拿到新数据都强制先跑一遍结构体检、匹配率统计和量级校验这三步再动手画图。希望这份拆解能帮你少走一段弯路把这份数据集真正跑起来。本文还有配套的精品资源点击获取