资讯详情

基于Python的中美疫情数据可视化分析与展示源码实战

📅 2026/10/3 13:25:20 | 华诺云谱 👁 阅读
基于Python的中美疫情数据可视化分析与展示源码实战
简介这份资源是一套面向Python数据分析初学者与可视化实践者的完整项目源码围绕中美两国疫情数据展开处理与展示适合用作课程设计、毕业设计参考或数据分析练手案例。压缩包共19个文件约145KB其中7个HTML页面承担可视化结果展示6个Python脚本负责数据清洗、预测与图表生成4个Excel和1个CSV文件提供中美及分省疫情原始数据另有说明文档辅助理解项目结构。项目覆盖国内疫情、全球疫情、中美对比以及中国与美国未来14天新增预测等分析模块读者可借此掌握从数据读取、指标计算到网页呈现的完整链路并参考预测脚本的实现思路。目前已有296人学习体量轻便便于快速运行与二次修改。1. 中美疫情数据可视化到底在做什么从一份 CSV 到能讲故事的看板很多人第一次接触「基于Python的中美疫情数据可视化分析与展示源码」这个标题脑子里浮现的是几张折线图加一个网页。真动手做过就知道难点从来不是画图而是数据从哪来、怎么对齐、怎么让两张不同口径的表能放在同一张图上比。中美两国的疫情数据在统计口径、更新频率、字段命名上差异极大直接 concat 会得到一堆 NaN 和错位的日期。这个方向真正解决的问题是把两份异构的公开数据整理成统一结构再用 Python 做清洗、聚合最后用可视化把趋势、峰值、阶段性差异讲清楚。适合有 Python 基础、想做一个完整数据项目练手的人也适合需要快速搭一个数据看板原型的开发者。下面这套路径我实际跑过从环境到出图到排错能照着复现。2. 数据获取与清洗中美两张表怎么对齐到同一根时间轴上2.1 数据源的字段差异与统一策略中美疫情数据最常见的来源是两类一类是按日期累计的全国汇总表字段通常是date、confirmed、deaths、recovered另一类是按州/省拆分的明细表多一层state或province维度。两边的坑在于美国数据常用mm/dd/yy格式中国数据常用yyyy-mm-dd美国累计数偶尔出现回退数据修正中国数据在早期有过统计口径调整。统一策略是先把日期全部转成datetime64再按天重采样累计值用cummax处理回退避免曲线出现负增长。import pandas as pd def load_and_clean(path, date_col, value_cols, regionNone): df pd.read_csv(path) # 日期统一兼容两种常见格式 df[date_col] pd.to_datetime(df[date_col], formatmixed, dayfirstFalse) df df.sort_values(date_col) # 累计值回退修正取历史最大值防止曲线抖动 for col in value_cols: df[col] df[col].cummax() if region: df df[df[region] region] df df.set_index(date_col).resample(D).ffill().reset_index() return df[[date, confirmed, deaths]]这段代码的关键参数是formatmixed它能自动识别多种日期格式省去手写映射。cummax是处理数据修正的核心没有它你会看到某天新增为负的玄学曲线。resample(D).ffill()保证两张表在相同日期索引上对齐缺失日向前填充。注意如果原始数据是新增值而非累计值先去重再累加不要直接 cummax。2.2 用 Pandas 做中美数据合并与派生指标对齐之后不要急着画图先算几个真正有分析价值的派生指标每百万人确诊、病死率、7 日滚动新增。中美人口基数差异巨大绝对数值对比没有意义必须归一化。7 日滚动能抹平周末上报延迟带来的锯齿。US_POP 331_000_000 CN_POP 1_412_000_000 def add_metrics(df, pop): df[per_million] df[confirmed] / pop * 1_000_000 df[cfr] df[deaths] / df[confirmed].replace(0, pd.NA) df[new_7d] df[confirmed].diff().rolling(7).mean() return df us add_metrics(load_and_clean(us.csv, date, [confirmed,deaths], United States), US_POP) cn add_metrics(load_and_clean(cn.csv, date, [confirmed,deaths], China), CN_POP) merged pd.concat([us.assign(countryUS), cn.assign(countryCN)], ignore_indexTrue)per_million是跨国家对比的唯一合理口径cfr在早期数据里会偏高因为分母滞后建议只取确诊数大于 1000 之后的区间。new_7d用diff加rolling注意第一周会是 NaN画图时 dropna 或从第 8 天开始截取。合并时用assign加国家标签比手动加列更干净。3. 可视化实现用 Matplotlib 和 Pyecharts 各画一版对比看板3.1 Matplotlib 静态图适合报告和论文的四个必画图静态图的价值在于可复现、可嵌入文档。我一般会画四张累计确诊对比、每百万人确诊对比、7 日新增双轴图、病死率随时间变化。前两张用折线第三张用面积加折线第四张用散点加趋势线。import matplotlib.pyplot as plt import matplotlib.dates as mdates fig, axes plt.subplots(2, 2, figsize(14, 9)) for country, grp in merged.groupby(country): axes[0,0].plot(grp[date], grp[confirmed], labelcountry) axes[0,1].plot(grp[date], grp[per_million], labelcountry) axes[1,0].plot(grp[date], grp[new_7d], labelcountry) axes[1,1].scatter(grp[date], grp[cfr], s4, labelcountry) axes[0,0].set_title(Cumulative Confirmed) axes[0,1].set_title(Confirmed per Million) axes[1,0].set_title(7-Day Rolling New Cases) axes[1,1].set_title(Case Fatality Rate) for ax in axes.flat: ax.xaxis.set_major_formatter(mdates.DateFormatter(%Y-%m)) ax.legend() plt.tight_layout() plt.savefig(covid_compare.png, dpi150)figsize和dpi决定输出清晰度报告用 150 足够印刷用 300。mdates.DateFormatter控制横轴刻度不设置会挤成一团。scatter的s4是点大小病死率散点太大会糊成一片。注意cfr在确诊为 0 的日期是 NAMatplotlib 会自动断开这是期望行为。3.2 Pyecharts 交互看板把折线图变成可缩放的网页如果目标是展示而非印刷Pyecharts 更合适它生成的 HTML 可以缩放、悬停看数值。核心是用Line加Timeline或Grid做多图联动。下面是一个双国家折线的最小可跑版本。from pyecharts import options as opts from pyecharts.charts import Line def build_line(df, metric, title): line Line(init_optsopts.InitOpts(width900px, height500px)) for country, grp in df.groupby(country): line.add_xaxis(grp[date].dt.strftime(%Y-%m-%d).tolist()) line.add_yaxis(country, grp[metric].round(2).tolist(), is_smoothTrue, is_symbol_showFalse) line.set_global_opts( title_optsopts.TitleOpts(titletitle), datazoom_opts[opts.DataZoomOpts(range_start60, range_end100)], tooltip_optsopts.TooltipOpts(triggeraxis), yaxis_optsopts.AxisOpts(type_log if metricconfirmed else value) ) return line build_line(merged, per_million, Confirmed per Million).render(per_million.html)DataZoomOpts的range_start60表示默认只显示后 40% 的时间段因为早期数据噪声大。is_smoothTrue让曲线平滑但会轻微失真分析场景建议关掉。yaxis_opts里对累计确诊用对数轴否则中国曲线会被压平。render输出独立 HTML不依赖服务器直接浏览器打开即可。4. 避坑与排查数据可视化项目里最容易翻车的五个地方4.1 日期解析失败导致整条曲线错位现象合并后某些日期出现重复或缺失折线图出现垂直跳变。原因中美数据一个用2020/1/1一个用01-01-2020pd.to_datetime默认按美式解析把03/04当成 3 月 4 日而非 4 月 3 日。解决显式指定format或先用formatmixed加dayfirst参数逐列验证打印df[date].head(20)人工确认。4.2 累计值回退被当成负增长画进图里现象新增曲线出现深 V 负值。原因数据源做了历史修正累计数下调。解决对累计列做cummax新增列用diff后把负值 clip 到 0再 rolling。不要直接对原始累计值画 diff。4.3 人口基数用错导致每百万人指标差一个量级现象中国每百万人确诊看起来比美国低很多但实际趋势相反。原因把中国人口写成 14 亿但单位用了「万」或者美国人口用了 3.3 亿却除以了 100 万两次。解决统一用「人」为单位per_million confirmed / pop * 1_000_000写完后手动验算一条100 万确诊 / 3.31 亿 ≈ 3021。4.4 Pyecharts 在 Jupyter 里不显示或空白现象render_notebook()调用后无图。原因JupyterLab 与 Pyecharts 版本不匹配或缺少pyecharts-jupyter-installer。解决改用render(out.html)输出文件再打开或者固定pyecharts2.0.3加jupyterlab扩展。不要在生产看板里依赖 notebook 内嵌。4.5 中文字体缺失导致标题和标签变方块现象Matplotlib 图上中文全是方框。原因默认字体不含 CJK。解决plt.rcParams[font.sans-serif] [SimHei]或[Noto Sans CJK SC]同时plt.rcParams[axes.unicode_minus] False修复负号。Linux 服务器上先fc-list :langzh确认有中文字体再设。5. 进阶技巧把静态脚本变成可复用的数据管道5.1 用配置文件驱动多国对比避免硬编码写到后面你会发现每加一个国家就改一次代码很蠢。我一般会抽一个config.yaml把数据路径、人口、字段映射、颜色都放进去主脚本只读配置循环处理。这样换数据源或加国家不用动核心逻辑。import yaml with open(config.yaml) as f: cfg yaml.safe_load(f) frames [] for name, meta in cfg[countries].items(): df load_and_clean(meta[path], meta[date_col], meta[value_cols], meta[region]) df add_metrics(df, meta[population]) frames.append(df.assign(countryname)) merged pd.concat(frames, ignore_indexTrue)config.yaml里每个国家一个块population写整数value_cols写列名列表。这样新增国家只需加一段配置不动 Python。注意 YAML 缩进必须用空格Tab 会报错。5.2 验证数据质量的三行检查出图前跑三行检查能省掉大量返工merged.groupby(country)[date].agg([min,max,count])看时间范围是否一致merged.isna().sum()看缺失分布merged.groupby(country)[confirmed].apply(lambda s: (s.diff() 0).sum())看还有没有负增长。这三行跑完没问题图基本不会翻车。5.3 一个我常犯的错早期我总想把所有指标塞进一张图结果读者什么都看不清。后来强迫自己一张图只讲一件事对比就只放对比趋势就只放趋势。看板不是数据仓库是叙事工具。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑