简介:新冠肺炎疫情数据分析与可视化课设项目,是一套经导师指导获评98分的完整毕业设计/课程设计参考。面向计算机、电子信息工程、数学等专业学生,适合期末大作业、毕设或竞赛备赛,涵盖数据获取、清洗、分析与可视化全流程。压缩包共57个文件、约3.94MB,包含17个Python脚本(爬虫、情感分析、Logistic预测等)、2个Jupyter Notebook、5个CSV数据文件、5个HTML页面及配套JS可视化组件、16张结果图,并附docx报告;目录按数据、脚本、模板、结果划分,便于对照学习。项目实现微博疫情评论爬取与NLP处理、国内外时序预测、省级分布以及中国/世界地图动态可视化,可直接复现并用于扩展。已有424人学习,适合想快速搭建疫情数据分析项目或参考高分课设写法的人群。
1. 疫情数据分析课设笔记:一个 98 分的全链路项目长什么样
第一次打开这套代码时,我以为是"爬虫 + 图表"的普通缝合怪,拆完才发现完全是另一回事。项目以新冠肺炎疫情公开数据为素材,把微博评论爬取、中文分词、情感打分、TF-IDF 关键词提取、逻辑斯蒂增长模型预测、ECharts 地图大屏串成了一条完整链路,后端用 Flask 提供页面服务,数据层落在 5 张 CSV 上,分析和预测则在两个 Jupyter Notebook 里可以做交互复现。适合计算机、电子信息工程、数学专业的学生拿来做课程设计、期末大作业或毕业设计的参考资料。这篇笔记按"架构—核心代码—踩坑—改造"的顺序,讲清楚它值不值得下载、怎么跑、怎么改成自己的。
2. 项目架构与目录拆解:爬虫、NLP、预测、可视化四条主线怎么组织
2.1 从压缩包到项目树:先认清每个目录干什么
先说结论:这套代码不是单一脚本,而是把"采集 → 处理 → 分析 → 可视化 → 展示"分成了多个独立脚本和目录。拿到压缩包解压后,顶层是 COVID-19-NLP-vis-master 目录,里面混着 ipynb、py、html、csv、json 和虚拟环境残留文件。初次看容易懵,按功能重排之后长这样:
COVID-19-NLP-vis-master/ ├── server.py # Flask 入口,承担页面路由与数据接口 ├── templates/ # HTML 模板与前端渲染脚本 │ ├── index.html # 首页大屏骨架 │ ├── analyse.html # 疫情时序分析页 │ ├── NLP.html # NLP 舆情分析页 │ ├── render.js # 图表渲染统一入口 │ ├── calendar.js # 日历热力图配置 │ └── weibolines.js # 微博舆论走势图配置 ├── notebooks/ # 两个核心分析 Notebook │ ├── 疫情分析和预测部分.ipynb │ └── NLP.ipynb ├── dataSets/ # 全部静态数据 CSV │ ├── china_provincedata.csv │ ├── countrydata.csv │ ├── yqkx_data-5_21.csv │ ├── weiboComments-5_21.csv │ └── API_SP.POP.TOTL_DS2_zh_csv_v2_1075183.csv ├── scripts/ # 爬虫与分析脚本 │ ├── spider-yqkx.py # 疫情快讯爬虫 │ ├── weibo_战疫情爬虫_spider.py │ ├── weiboProcess.py # 微博数据处理 │ ├── weiboAnalyse.py # 微博分析主入口 │ ├── sentiments.py # 情感分析 │ ├── jiebafenci.py # 中文分词 │ ├── tfidf.py # TF-IDF 关键词 │ ├── wordData.py # 词频数据生成 │ ├── weiboWordData.py # 微博词云数据 │ ├── mergeweibos.py # 多源微博评论合并 │ ├── logistic.py # 逻辑斯蒂时序预测 │ ├── mapchina.py # 中国地图数据 │ ├── mapworld.py # 世界地图数据 │ ├── lineCountry.py # 国家趋势线图数据 │ └── hierarchy.py # 矩形树图数据 └── 新冠肺炎时序数据预测算法设计.docx这个结构透露出一个设计习惯:每个可视化图表都对应一个"数据生成脚本",render.js 只负责把数据渲染到前端。mapchina.py 生成省份分布数据,mapworld.py 生成世界分布,lineCountry.py 生成多国趋势线,hierarchy.py 生成矩形树图。脚本名即职责,后面改造时找代码非常快。
目录里还有两类容易忽略的文件:pyvenv.cfg 和 pip-selfcheck.json 是虚拟环境残留,说明开发者在某个虚拟环境里跑过;.gitignore 表明原项目用过 git 管理。这些文件不影响运行,但提醒你最好自己建一个干净的 venv,别直接用系统 Python,后面避坑章节会专门讲这个坑。
2.2 数据采集与存储:CSV 数据集是项目的"黑匣子"
数据层一共 5 张 CSV:china_provincedata.csv 是国内各省份的累计确诊、治愈、死亡数据;countrydata.csv 是国外各国疫情数据;yqkx_data-5_21.csv 是截至某日期的疫情快讯文本;weiboComments-5_21.csv 是采集到的微博评论原文;API_SP.POP.TOTL_DS2_zh_csv_v2_1075183.csv 是世界银行的人口数据,用来算每百万人感染率这类归一化指标。
为什么单独把数据层拎出来说?因为后面所有图表、预测、情感分析都从这 5 张表读数据,它们就是这个项目的黑匣子。如果哪天爬虫失效或 CSV 被改动,整个链路都会崩。血泪经验是:拿到项目先不急着跑脚本,先用 Pandas 检查每张表的列名、行数和时间字段的类型,避免后面被一堆 KeyError 追着跑。
import pandas as pd df = pd.read_csv("dataSets/weiboComments-5_21.csv", encoding="utf-8") print(df.shape) # 先看形状,确认数据量 print(df.dtypes) # 再看字段类型,确认日期列不是 object print(df.head(3)) # 最后看样例,确认中文没有乱码CSV 编码是这项目最常见的翻车点。文件虽然是 utf-8 保存的,但里面夹杂的中文标点、emoji、换行符都会让 read_csv 解析出问题。常见做法是先用上面的代码探结构,再对比 scripts 里各脚本读取时的 encoding 参数是否一致,不一致就统一改成 utf-8 加 errors="ignore"。
2.3 三条技术主线如何汇合到 Web 服务
拆完目录会发现,这个课设的内核其实是三条并行的技术主线。第一条是疫情数据分析与预测,核心脚本是 logistic.py,产出是时序趋势图和未来 14 天预测数据;第二条是微博舆情 NLP,核心是 sentiments.py、tfidf.py、jiebafenci.py,产出是正负情感占比、关键词排序和词云;第三条是可视化展示,核心是 Flask 的 server.py 与 templates 下的 ECharts 模板。最终由 server.py 把三者统一渲染成三个页面:index.html 做整体概览,analyse.html 做时序预测,NLP.html 做舆情分析。
数据流大概是这样的:爬虫脚本把微博评论和疫情快讯落盘成 CSV;scripts 里的分析脚本读 CSV,算出结果后直接塞进前端模板变量;服务端不存数据库,不写接口,所有数据交换发生在 Flask 渲染模板的那一刻。这个"脚本生成数据,Flask 统一喂给模板"的模式,是整套代码最值得抄的地方。很多课设把图表数据写死在 HTML 里,改一天数据就得改一次页面;这套代码把数据层和展示层拆开,二次开发时只需要替换 CSV 或改写脚本输出,页面几乎不用动。
3. 核心模块实战:时序预测与微博舆情分析的完整链路
3.1 时序预测核心:logistic.py 的逻辑斯蒂增长模型
疫情累计确诊曲线天然是一条 S 型曲线:前期指数增长,中期增速放缓,后期趋于饱和。这种形态最经典的拟合方式就是逻辑斯蒂增长模型,公式是 P(t) = K / (1 + e^(-r(t - t0)))。K 是环境容纳量,r 是增长率,t0 是拐点时间。scipy 的 curve_fit 可以直接做非线性最小二乘拟合,代码量非常小。
# logistic.py 核心逻辑(按项目场景还原) import numpy as np from scipy.optimize import curve_fit def logistic(t, K, r, t0): return K / (1 + np.exp(-r * (t - t0))) def fit_predict(dates, confirmed): x = np.arange(len(dates)) # 把日期映射成从 0 开始的序号 popt, _ = curve_fit( logistic, x, confirmed, p0=[confirmed[-1] * 2, 0.2, len(confirmed) / 2], maxfev=100000 ) # popt 依次是 K、r、t0 future_x = np.arange(len(confirmed), len(confirmed) + 15) pred = logistic(future_x, *popt) return predp0 里的初值设定是预测能否收敛的关键。K 取当前累计值的两倍,是假设最终规模至少在当前基础上翻倍;r 取 0.2 是传染病早期传播率的经验值;t0 取时间序列中点作为拐点初值。这三个初值如果偏离实际太远,curve_fit 会因为雅可比矩阵奇异直接抛 RuntimeError,这就是玄学调参的开始。我一般会先打印拟合曲线的 R 方,如果 R 方低于 0.95,说明数据形态不适合逻辑斯蒂,要考虑分段拟合或换成 Gompertz 模型。
这个代码对应压缩包里的《新冠肺炎时序数据预测算法设计.docx》,答辩时能把 K、r、t0 的物理意义讲清楚,比贴十页代码都加分。K 决定疫情最终规模,r 决定传播速度,t0 是增速由快到慢的转折点,这三个参数在公开疫情报道里都能找到对应描述,讲出来就是完整的算法设计闭环。
3.2 情感分析:sentiments.py 如何给微博评论打分
微博评论是典型的短文本,长度短、口语化严重、夹杂表情符号与网络新词。直接套深度学习模型既重又不稳定,这个项目选的是情感词典打分方案:先按标点把评论切成句子,再逐个匹配积极词和消极词,最后累加得分。
# sentiments.py 核心逻辑(按项目场景还原) import re POSITIVE_WORDS = {"加油", "致敬", "感谢", "平安", "相信", "必胜"} NEGATIVE_WORDS = {"害怕", "焦虑", "愤怒", "谣言", "封城", "感染"} def sentiment_score(text): score = 0 sentences = re.split(r"[,。!?;\n]", text) for sentence in sentences: for word in POSITIVE_WORDS: if word in sentence: score += 1 for word in NEGATIVE_WORDS: if word in sentence: score -= 1 return score这里的词典方案虽然粗糙,但用在课设场景反而合适:结果可解释,每条评论为什么是积极或消极都能追溯到具体词命中,写报告时直接可以列样例。如果你要把打分做得更细,常见做法是把词典换成知网情感分析用词表,并加入程度副词权重,比如"非常""有点"分别乘以 1.5 和 0.5。weiboAnalyse.py 会把这个分数按天聚合,输出到前端做舆论走势折线图。
3.3 TF-IDF 与 Jieba 分词:关键词提取和词云生成
做不了全文向量化的时候,TF-IDF 是短文本主题挖掘最稳的工具。tfdif.py 的思路是先把所有微博评论拼接成文档集,用 jieba 分词后丢给 sklearn 的 TfidfVectorizer,取权重最高的 TopN 词输出。
# tfidf.py 核心逻辑(按项目场景还原) import jieba from sklearn.feature_extraction.text import TfidfVectorizer def extract_keywords(docs, top_n=20): corpus = [" ".join(jieba.cut(doc)) for doc in docs] vectorizer = TfidfVectorizer(max_features=5000) matrix = vectorizer.fit_transform(corpus) # 按 TF-IDF 均值排序,取出前 N 个词作为全局热点 mean_weights = matrix.mean(axis=0).A1 indices = mean_weights.argsort()[::-1][:top_n] return [(vectorizer.get_feature_names_out()[i], mean_weights[i]) for i in indices]分词和 TF-IDF 的顺序要注意:必须先分词再用空格拼接,TfidfVectorizer 才能正确切出词项。如果直接传原始短文本,英文场景能用,中文会被切成一整个长串,提取结果基本是乱码级别的废数据。wordData.py 和 weiboWordData.py 的差别就在这:前者做全局词频,后者按微博原文再聚合一次,两个结果分别喂给 index.html 和 NLP.html 的词云组件。
4. 可视化大屏与 Flask 服务:server.py 与 render.js 的前后端串联
4.1 server.py 的路由设计:一个 Flask 应用怎么把图表喂给模板
server.py 是这个项目的总线。它不涉及具体算法,只做三件事:读取 scripts 产出的 JSON 或 pandas 对象、定义路由、在 render_template 时把数据作为参数传给前端。这个设计让后端分析脚本可以独立运行和调试,页面渲染失败时不用怀疑算法层。
# server.py 路由设计(按项目场景还原) from flask import Flask, render_template import pandas as pd app = Flask(__name__) @app.route("/") def index(): df = pd.read_csv("dataSets/china_provincedata.csv") province_names = df["province"].tolist() confirmed_values = df["confirmed"].tolist() return render_template( "index.html", provinces=province_names, confirmed=confirmed_values ) @app.route("/analyse") def analyse(): # 读取 logistic.py 的预测结果,传给时序分析页 return render_template("analyse.html", data=prediction_json) @app.route("/nlp") def nlp(): return render_template("NLP.html", wordcloud=word_cloud_json)路由和数据变量的对应关系非常直白:index 对应省份地图,analyse 对应时序预测,nlp 对应词云和情感分布。值得注意的一点是,render_template 传参时用了和前端 JS 变量几乎同名的 key,这样在模板里写var data = {{ confirmed | tojson }}时,前后端变量名一目了然,不需要额外维护一份字段映射文档。
4.2 ECharts 地图与日历热力图:从 JSON 数据到图表渲染
模板目录里的 render.js 是所有 ECharts 图表的统一初始化入口。它从模板变量拿到 JSON 后,按图表类型分发到不同配置函数。日历热力图 calendar.js 是这里面最有视觉效果的一个,它把某段时间内每天的微博讨论数量映射成颜色深浅,一眼能看出舆论关注度的峰值日。
// calendar.js 配置核心(按项目场景还原) const calendarHeatmap = echarts.init( document.getElementById("calendar-chart") ); calendarHeatmap.setOption({ visualMap: { min: 0, max: 2000, calculable: true, inRange: { color: ["#e8e8e8", "#f5a623", "#d0021b"] } }, calendar: { range: "2020-01-20", cellSize: ["auto", 20] }, series: [{ type: "heatmap", coordinateSystem: "calendar", data: calendarData // 格式: [[date, value], ...] }] });visualMap 的 min 和 max 不要用固定值,否则数据量级变了颜色就全偏。常见做法是在后端算好四分位数,把 max 设为 P75 或 P90,让颜色梯度始终分布在有效区间。calendar.js 和 weibolines.js 的区别是前者关注"哪天讨论多",后者关注"积极消极情绪随时间的比例变化",一个是热力,一个是双折线,正好对应舆情分析的广度和深度。
4.3 Notebook 里的另一套可视化:交互复现与报告素材
scripts 目录跑出来的是最终大屏,而两个 Notebook 承担的是"过程可复现"的角色。疫情分析和预测部分.ipynb 把时序预测拆成一步步的细胞:读 CSV、画累计曲线、拟合逻辑斯蒂、输出预测表,每一步都有图,适合放进课设报告当截图。NLP.ipynb 则把情感分析和 TF-IDF 排序的过程做成演示,评委打开 Notebook 就能看到中间结果。
这两个 Notebook 本质上是 scripts 里算法的教学版,代码基本一致,但输出粒度更细。如果你要交课设,我的建议是:大屏页面负责"好看",Notebook 负责"可信"。答辩现场打开 Notebook 重新跑一遍分析流程,比放着做好的大屏讲更有说服力,也更能应对"这个结果怎么来的"这类提问。
5. 避坑指南:跑通这个项目的 5 个常见问题与排查日志
5.1 import 报错:虚拟环境残留与依赖未装齐
现象:直接跑 server.py 或某个 scripts 脚本,第一行 import pandas 就抛 ModuleNotFoundError,或者明明装了 pandas 却说没有 sklearn。
原因:压缩包里虽然带有 pyvenv.cfg 和 pip-selfcheck.json,但这些只是之前虚拟环境的残留配置,不代表依赖被一起打包了。系统 Python 环境又没有安装项目需要的 scipy、sklearn、flask、jieba 等库。
解决:创建一个干净虚拟环境,用 requirements 逐个安装。项目没附 requirements.txt 的话,按 import 清单手动安装一遍,核心依赖就以下几组:
python -m venv venv source venv/bin/activate # Windows 下是 venv\Scripts\activate pip install flask pandas scipy scikit-learn jieba # 验证导入 python -c "import flask, pandas, scipy, sklearn, jieba; print('ok')"顺带说一句,如果在安装 scipy 时遇到编译报错,优先换用预编译 wheel 版本,不要自己折腾源码编译。这个坑在 Windows 上尤其常见,我个人经验是直接装 anaconda 发行版能省掉一半烦恼。
5.2 中文乱码与 CSV 解析失败
现象:read_csv 读进去的 DataFrame 字段全是乱码,或者直接抛 UnicodeDecodeError;部分脚本用 utf-8 读取正常,另一部分用 gbk 读取正常,互相冲突。
原因:数据文件是从微博页面抓取后直接落盘的,既有 emoji 又有中文标点,部分文件实际编码不是声明的那样。更讨厌的是,同一个 CSV 里可能混着多种编码的内容。
解决:统一用 utf-8-sig 读取,并加上 errors 参数忽略无法解析的字节。写回文件时也用 utf-8-sig,这样 Excel 打开也不会乱码。如果 Pandas 解析到某一行时报 ParserError,先跳过错误行再定位脏数据:
df = pd.read_csv( "dataSets/weiboComments-5_21.csv", encoding="utf-8-sig", engine="python", on_bad_lines="skip" )5.3 ECharts 地图不显示:JS 加载顺序问题
现象:页面能打开,折线图柱状图都正常,但中国地图和世界地图区域是空白,控制台报 "geo is not defined" 或者地图数据未找到。
原因:ECharts 从 5.0 开始不再内置地图数据,需要额外注册 GeoJSON。项目里如果用旧版方式引入地图,或者 script 标签加载顺序不对,render.js 执行时地图数据还没注册完。
解决:检查 HTML 里 ECharts 的引入顺序,地图脚本必须在 render.js 之前:
<script src="echarts.min.js"></script> <script src="echarts-countries-js/china.js"></script> <script src="render.js"></script>如果项目里根本没有 china.js 这种地图注册文件,就直接删掉地图初始化逻辑,把 map 改成 bar,用柱状图展示省份数据,效果一样好看且省去外部依赖。
5.4 脚本与 Notebook 路径不一致导致数据读不到
现象:Notebook 里运行一切正常,但到项目根目录跑 scripts 里的同款脚本,FileNotFoundError,找不到 dataSets 下的 CSV。
原因:Notebook 的当前工作目录是 notebooks 目录本身,而 scripts 脚本期望从项目根目录运行。两边的相对路径基准不一样。
解决:不需要改代码逻辑,只需要统一运行位置,全部从项目根目录执行:
python scripts/logistic.py python server.py如果脚本内部写死了相对路径,更好的做法是在脚本开头用 os.path.dirname 动态计算项目根目录,把路径前缀补全,这一步对后续二次开发几乎是必须的。我在改造项目时每次都强制走一遍这个步骤,防止换机器后路径崩掉。
5.5 爬虫失效的应急处理:用静态数据替代实时抓取
现象:运行 weibo_战疫情爬虫_spider.py 或 spider-yqkx.py,请求超时、登录校验失败,或者抓到一半被限流。
原因:这类社交媒体爬虫非常依赖页面结构和反爬机制,项目里提前采集好的 CSV 没法永久反映最新页面结构。今天能跑通,明天可能就失效了。
解决:只要不是非做爬虫展示不可,课设阶段直接用 dataSets 里已有的 CSV 做分析,爬虫脚本当作加分项展示即可。我一般会在报告里注明"数据来自公开渠道的历史采集文件",把爬虫定位为数据获取方式的一种说明,而不是系统核心依赖。这样既不会在答辩现场翻车,也保留了完整链路。
6. 二次开发:把疫情分析项目改造成通用舆情系统
6.1 数据源解耦与接口抽象
这套代码最大的可改造点,是把疫情数据源和展示逻辑解耦。数据层从 CSV 换成任意评论数据或公开数据集,分析脚本基本可以原样复用。比如把 weiboComments CSV 换成某短视频平台评论导出表,情感分析和 TF-IDF 提取完全不用改,前端只需要把"确诊""加油"这类词换成新主题的词典。
我会先把 sentiments.py 的词典抽成外部 JSON 文件,再给每个分析脚本加一个统一的输入参数,改造时只动配置文件不动代码:
# config.json 按主题配置词典与停用词 { "positive_words": ["支持", "理解", "满意"], "negative_words": ["投诉", "失望", "虚假"] }6.2 加入定时调度与增量更新
如果想让项目真正"活"起来,思路是给爬虫和分析加一个定时任务。每天凌晨用 cron 或 GitHub Actions 触发爬虫抓取昨天的评论,追加到 CSV 尾部,再跑一次情感分析和词云统计,页面数据就会自动滚动更新。
这个改造完成之后,回头再看这份课设,它已经不只是一个 98 分的作业,而是一个可以持续扩展的舆情分析底座。我从这个项目里学到的经验是:凡是数据、逻辑、展示三个层次清晰的项目,无论评分多高,都能在半小时内换成自己的业务主题。从那以后我每次接手外部项目,都会强制走一遍"找数据入口 → 理清脚本职责 → 跑通最小链路"这个过程,再决定要不要动代码。希望这份拆解能帮你在课程设计里少走一段弯路,也祝你顺利跑通这套疫情数据分析与可视化项目。
本文还有配套的精品资源,点击获取