據(jù)分析與可視化Python課設(shè):從數(shù)據(jù)清洗到閉環(huán)報(bào)告)
簡(jiǎn)介一份面向計(jì)算機(jī)、電子信息工程、數(shù)學(xué)等專業(yè)大學(xué)生的新冠肺炎疫情數(shù)據(jù)分析與可視化完整課設(shè)項(xiàng)目可用于課程設(shè)計(jì)、期末大作業(yè)或畢業(yè)設(shè)計(jì)參考適合需要從零搭建數(shù)據(jù)采集、清洗、分析與可視化流程的讀者。項(xiàng)目包共57個(gè)文件包含17個(gè)Python腳本涉及微博輿情爬蟲、疫情數(shù)據(jù)爬取、分詞、邏輯回歸預(yù)測(cè)、地圖與詞云可視化2個(gè)Jupyter Notebook疫情分析與預(yù)測(cè)、NLP處理以及5個(gè)CSV疫情數(shù)據(jù)集、5個(gè)HTML交互頁(yè)面、算法設(shè)計(jì)Word報(bào)告和多張結(jié)果圖片整體約3.94MB。已有424人學(xué)習(xí)下載。借助這份高分作品讀者可以快速掌握新冠時(shí)序預(yù)測(cè)與情感分析的具體實(shí)現(xiàn)理解數(shù)據(jù)爬取、預(yù)處理、模型構(gòu)建、可視化展示的完整鏈路并直接復(fù)用其中代碼和圖表生成方案有效節(jié)省課設(shè)開發(fā)與報(bào)告撰寫時(shí)間。1. 從 zip 解壓到跑通只算開始疫情課設(shè)要的是能說清的分析閉環(huán)很多人拿到“新冠肺炎疫情數(shù)據(jù)分析與可視化python完整課設(shè)和代碼報(bào)告.zip”之后第一件事是解壓、裝庫(kù)、運(yùn)行看到彈出折線圖就以為完事了。真正到答辯或驗(yàn)收時(shí)老師盯著圖問一句“這個(gè)日新增是你算出來的還是文件里直接帶的”“地圖上的省份名和你數(shù)據(jù)里的省份對(duì)不對(duì)得上”很多人當(dāng)場(chǎng)垮掉。這門課設(shè)的核心不是“能跑出圖”而是“數(shù)據(jù)怎么來→清洗成什么結(jié)構(gòu)→圖上畫的是什么→結(jié)論怎么從圖里長(zhǎng)出來”整條鏈路閉環(huán)?!靶鹿诜窝滓咔閿?shù)據(jù)分析與可視化python”這串詞說白了就是拿一份公開的疫情表格用 pandas 清洗用 pyecharts 畫趨勢(shì)、畫地圖再用一兩段指標(biāo)或模型把結(jié)論寫進(jìn)報(bào)告。適合剛學(xué)完 Python 基礎(chǔ)、要交課程設(shè)計(jì)或者想在簡(jiǎn)歷里放一個(gè)“從數(shù)據(jù)到可視化到報(bào)告”完整作品的人。如果已經(jīng)有底子直接跳到第 5 章避坑清單也不虧。2. 數(shù)據(jù)獲取與清洗把疫情 csv 揉成一張能畫圖的長(zhǎng)表公開疫情數(shù)據(jù)和你在教程里看到的小樣例最大的區(qū)別是“它有手有腳”要么寬表里橫著一排日期列要么長(zhǎng)表動(dòng)輒幾十萬(wàn)行字段名也不是同一個(gè)風(fēng)格。做這個(gè)課設(shè)第一步不是畫圖而是定口徑。先搞清楚我們要什么一張“日期 國(guó)家 累計(jì)確診 累計(jì)死亡 累計(jì)康復(fù)”的干凈長(zhǎng)表再加一個(gè)“日新增”列后面所有圖表都從這里出。2.1 先看清表格結(jié)構(gòu)寬表和長(zhǎng)表是兩種世界拿到 zip 后先別急著寫畫圖代碼打開數(shù)據(jù)文件看前幾行。疫情公開數(shù)據(jù)常見兩種存儲(chǔ)格式寬表每行是一個(gè)國(guó)家或省份后面的列是連續(xù)的日期格子里的值是“截止該日期的累計(jì)確診”。這種表人類看著方便但 pandas 畫圖很難直接消費(fèi)。長(zhǎng)表只有幾列一般包含 Province/State、Country/Region、Date、Confirmed、Deaths、Recovered。這種結(jié)構(gòu)對(duì) pandas 最友好groupby、篩選、合并都不容易出錯(cuò)。先做這一步import pandas as pd raw pd.read_csv(data/covid_global.csv, nrows5) print(raw.columns.tolist()) print(raw.head())nrows5 只讀前 5 行目的是快速確認(rèn)列名、日期格式和分隔符。如果你拿到的文件是 xlsx 或 xls把 pd.read_csv 換成 pd.read_excel 即可兩者后續(xù)處理一致。這一步花不了一分鐘但能避免后面幾十次報(bào)錯(cuò)。寬表和長(zhǎng)表沒有誰(shuí)好誰(shuí)壞但處理路徑完全不同。寬表適合用 melt 壓縮成行長(zhǎng)表適合直接 rename 和 groupby。先判斷自己手里是哪種再?zèng)Q定走哪個(gè)清洗分支比強(qiáng)行套網(wǎng)上的教程代碼靠譜得多。見過不少翻車現(xiàn)場(chǎng)手里是寬表硬套長(zhǎng)表的代碼跑出來的圖全是一條水平線因?yàn)?pandas 把整列日期當(dāng)成了一個(gè)單獨(dú)字段。2.2 用 pandas 三行命令把寬表變成可計(jì)算的長(zhǎng)表寬表轉(zhuǎn)長(zhǎng)表是疫情課設(shè)里最高頻的操作。以一份全球累計(jì)確診寬表為例結(jié)構(gòu)大概是Country/Region 作為第一列后面跟著 1/22/20、1/23/20…… 這種日期列。轉(zhuǎn)換代碼如下long_df raw.melt( id_vars[Province/State, Country/Region, Lat, Long], var_namedate, value_nameconfirmed, ) long_df[date] pd.to_datetime(long_df[date], format%m/%d/%y) long_df ( long_df.groupby([Country/Region, date], as_indexFalse)[confirmed] .sum() .sort_values([Country/Region, date]) ) long_df[daily_new] ( long_df.groupby(Country/Region)[confirmed] .diff() .fillna(0) .clip(lower0) )這段代碼的邏輯分四步melt 把幾十個(gè)日期列壓縮成 date 和 confirmed 兩列pd.to_datetime 指定 format 把美國(guó)式日期轉(zhuǎn)成 pandas 的 datetime 類型groupby 按“國(guó)家 日期”聚合解決同一個(gè)國(guó)家下分省份、分州導(dǎo)致多行的問題最后用 diff 算相鄰日期的差值得到每日新增。參數(shù)說明format 里的 %m/%d/%y 必須和文件里的日期格式一致如果文件里是 2020-01-22就要改成 format%Y-%m-%d。groupby 里的 sum() 把同一國(guó)家不同省份當(dāng)日數(shù)據(jù)合并如果某國(guó)數(shù)據(jù)是長(zhǎng)表且已經(jīng)只有國(guó)家維度這步也不會(huì)出錯(cuò)因?yàn)橐粋€(gè)“國(guó)家日期”只有一行。clip(lower0) 是為了去掉 diff 算出來的負(fù)值——后文避坑章會(huì)細(xì)說。2.3 清洗的隱藏問題重復(fù)行、負(fù)值、日期格式寬表轉(zhuǎn)成長(zhǎng)表只是第一步。真正讓課設(shè)翻車的往往是下面這些看起來不起眼的小問題。重復(fù)行非常常見多個(gè)數(shù)據(jù)源拼接時(shí)同一國(guó)家同一日期可能出現(xiàn)兩次。如果不去重日新增會(huì)被翻倍。去重代碼在聚合前后都要執(zhí)行一次long_df long_df.drop_duplicates( subset[Country/Region, date], keeplast )keeplast 表示后面出現(xiàn)的覆蓋前面出現(xiàn)的適合“后更新的數(shù)據(jù)更準(zhǔn)”的場(chǎng)景。注意 subset 不包含 confirmed因?yàn)槲覀円氖恰皣?guó)家日期”維度上去重。日期格式統(tǒng)一要在畫圖之前完成。如果不轉(zhuǎn) datetime直接畫圖時(shí)橫軸會(huì)被當(dāng)成字符串順序會(huì)是 2020-01-01、2020-02-01…… 這種詞典序節(jié)假日和換月的地方排序亂掉。轉(zhuǎn)成 datetime 后matplotlib 和 pyecharts 都能自動(dòng)處理時(shí)間軸。還有一個(gè)容易忽略的點(diǎn)file 編碼。pandas 默認(rèn)按 utf-8 讀但很多公開 csv 是 ANSI 編碼。讀取時(shí)可以顯式指定long_df pd.read_csv(data/covid_global.csv, encodingutf-8)如果報(bào) UnicodeDecodeError改成 encodinggbk 或 encodinglatin1 逐個(gè)試。清洗完導(dǎo)出時(shí)我會(huì)用 utf-8-sig 而不是 utf-8因?yàn)?utf-8-sig 會(huì)在文件開頭寫入 BOMExcel 打開中文不會(huì)亂碼long_df.to_csv(data/covid_clean.csv, indexFalse, encodingutf-8-sig)indexFalse 是為了不把 pandas 的行號(hào)寫進(jìn)文件utf-8-sig 是課設(shè)報(bào)告里 Word 引用表格的后悔藥。提示清洗階段保存一份 covid_clean.csv之后所有畫圖和建模都從這里讀不要再碰原始文件。這樣一旦分析出錯(cuò)能很快區(qū)分是數(shù)據(jù)問題還是代碼問題而不是每次從頭跑。3. 可視化用 pyecharts 做報(bào)告能直接引用的趨勢(shì)圖和地圖數(shù)據(jù)清洗完接下來進(jìn)入視覺部分。選對(duì)可視化庫(kù)課設(shè)的觀感能直接提升一個(gè)檔次。3.1 為什么是 pyecharts 而不是 matplotlibmatplotlib 適合論文里那種嚴(yán)謹(jǐn)?shù)男〕叽鐖D但如果要做課設(shè)答辯或可視化大屏展示pyecharts 更合適pyecharts 本質(zhì)是把 echarts 數(shù)據(jù)可視化 的能力搬進(jìn)了 python輸出是一個(gè)自包含的 html 文件鼠標(biāo)懸停有提示框圖可以縮放、拖拽不需要前端功底就能拿到交互效果。報(bào)告里截圖用靜態(tài)圖答辯現(xiàn)場(chǎng)打開 html 給老師看交互兩種場(chǎng)景都覆蓋。另一個(gè)關(guān)鍵理由是地圖。pyecharts 的 Map 組件對(duì)國(guó)內(nèi)省份的中國(guó)地圖和全球國(guó)家地圖都有現(xiàn)成支持不需要自己找 GeoJSON、算投影。一套代碼下來趨勢(shì)圖、Top10 柱狀圖、省份地圖、時(shí)間線動(dòng)畫全是同一個(gè)庫(kù)的語(yǔ)法學(xué)習(xí)成本低很多。3.2 折線圖和柱狀圖把趨勢(shì)與 Top10 寫進(jìn)報(bào)告報(bào)告里最保險(xiǎn)、最不跳戲的三張圖全國(guó)或全球累計(jì)確診折線圖、每日新增折線圖、累計(jì)確診 Top10 國(guó)家柱狀圖。折線圖代碼from pyecharts.charts import Line from pyecharts import options as opts line Line(init_optsopts.InitOpts(width960px, height540px)) line.add_xaxis(date_labels) line.add_yaxis( 日新增確診, daily_values, is_smoothTrue, label_optsopts.LabelOpts(is_showFalse), linestyle_optsopts.LineStyleOpts(width3, color#d14a1e), ) line.set_global_opts( title_optsopts.TitleOpts(title日新增確診趨勢(shì)), tooltip_optsopts.TooltipOpts(triggeraxis, axis_pointer_typecross), datazoom_opts[opts.DataZoomOpts(range_start30, range_end100)], ) line.render(charts/line_daily.html)add_yaxis 里的 is_smoothTrue 讓折線平滑避免折線像鋸齒一樣扎眼label_opts 的 is_showFalse 是不在每個(gè)數(shù)據(jù)點(diǎn)上標(biāo)數(shù)字否則幾百個(gè)點(diǎn)全堆在圖上沒法看。datazoom_opts 是 pyecharts 的亮點(diǎn)圖表下方會(huì)出現(xiàn)一個(gè)縮放條默認(rèn) range_start30 表示只顯示后 70% 的數(shù)據(jù)老師拖縮放條就能看任意時(shí)間段細(xì)節(jié)。width 和 height 設(shè)置畫布尺寸報(bào)告里引用截圖時(shí)分辨率能撐得住。柱狀圖更簡(jiǎn)單但有個(gè)參數(shù)必須調(diào)from pyecharts.charts import Bar bar Bar() bar.add_xaxis(top10_countries) bar.add_yaxis(累計(jì)確診, top10_values) bar.set_global_opts( title_optsopts.TitleOpts(title累計(jì)確診 Top10 國(guó)家), xaxis_optsopts.AxisOpts( axislabel_optsopts.LabelOpts(rotate-15) ), ) bar.render(charts/bar_top10.html)rotate-15 是 x 軸標(biāo)簽旋轉(zhuǎn) 15 度。國(guó)名通常較長(zhǎng)不旋轉(zhuǎn)會(huì)疊在一起報(bào)告里截出來的圖全是黑坨坨。Top10 的選取很簡(jiǎn)單按確診總數(shù)排序取前 10 個(gè)國(guó)家名和數(shù)值先算好再喂給柱狀圖不要在 add_xaxis 里臨時(shí)篩選。3.3 中國(guó)地圖和時(shí)間線做出可視化大屏的觀感國(guó)內(nèi)省份熱力地圖是疫情課設(shè)的保留節(jié)目。代碼并不長(zhǎng)from pyecharts.charts import Map map_chart Map() map_chart.add( 累計(jì)確診, [list(z) for z in zip(province_names, province_values)], china, ) map_chart.set_global_opts( title_optsopts.TitleOpts(title國(guó)內(nèi)各省累計(jì)確診熱力), visualmap_optsopts.VisualMapOpts( min_0, max_int(province_values.max()), is_piecewiseTrue, pieces[ {min: 10000, color: #c12e2a}, {min: 1000, max: 9999, color: #fd8f42}, {min: 100, max: 999, color: #ffd45e}, {max: 99, color: #eaf6ee}, ], ), ) map_chart.render(charts/map_province.html)is_piecewiseTrue 配合 pieces 列表會(huì)把圖例分成幾個(gè)區(qū)間段而不是用一個(gè)連續(xù)色條。這樣設(shè)計(jì)的好處是低數(shù)值省份不會(huì)被高數(shù)值省份的顏色淹沒視覺效果更接近正式可視化大屏。pieces 里的 min、max、color 按自己數(shù)據(jù)量級(jí)改如果最大確診是 5 萬(wàn)就把第一檔的 min 改成 50000。如果想把地圖做成隨時(shí)間變化的動(dòng)畫用 Timelinefrom pyecharts.charts import Timeline timeline Timeline() for d in sample_dates: piece build_map_for_date(d) timeline.add(piece, time_pointd) timeline.add_schema(play_interval800, is_auto_playTrue) timeline.render(charts/timeline.html)build_map_for_date 是“傳一個(gè)日期返回一個(gè)該日期的 Map 實(shí)例”的函數(shù)你可以把上面的 Map 代碼包進(jìn)這個(gè)函數(shù)換數(shù)據(jù)源即可。add_schema 的 play_interval800 是自動(dòng)播放時(shí)每幀間隔 800 毫秒is_auto_playTrue 讓頁(yè)面打開后自動(dòng)播放。答辯演示到這一頁(yè)時(shí)地圖上色塊隨時(shí)間燃燒擴(kuò)散比任何靜態(tài)圖都有說服力這也是“python數(shù)據(jù)分析與可視化實(shí)踐”里最能體現(xiàn)工作量的一塊。4. 數(shù)據(jù)分析與模型用指標(biāo)和 SIR 模型把結(jié)論寫進(jìn)課設(shè)報(bào)告可視化解決“數(shù)據(jù)長(zhǎng)什么樣”分析解決“數(shù)據(jù)說明什么”。只畫圖不分析報(bào)告就沒有結(jié)論答辯時(shí)只能念圖例。這一章講三個(gè)能落地到課設(shè)報(bào)告的產(chǎn)出增長(zhǎng)率指標(biāo)、粗糙 R0、SIR 模型曲線。4.1 從圖到結(jié)論環(huán)比增速與一個(gè)粗糙 R0累計(jì)確診從 1 萬(wàn)漲到 2 萬(wàn)和從 100 萬(wàn)漲到 101 萬(wàn)同樣都漲了 1 萬(wàn)但傳播勢(shì)頭完全不同。所以要算環(huán)比增長(zhǎng)率china clean_df[clean_df[country] China].copy() china china.sort_values(date) china[growth_rate] china[confirmed].pct_change().fillna(0) * 100 china[daily_new_7d] ( china[daily_new].rolling(7, min_periods1).mean() ) china[r0_approx] ( china[daily_new].rolling(7).mean() / china[confirmed].shift(1).rolling(7).mean() ).fillna(0)pct_change() 自動(dòng)算相鄰日期的百分比變化乘以 100 變成百分比。growth_rate 在疫情早期很高后期趨近于 0報(bào)告里可以寫“增長(zhǎng)率從早期的高位回落到低位說明傳播被逐步壓制”。r0_approx 是我習(xí)慣用的粗糙估計(jì)用 7 天平均日新增除以 7 天前的累計(jì)確診表示每 1 個(gè)已感染者在一周內(nèi)平均催生出的新感染人數(shù)。這個(gè)值不是流行病學(xué)嚴(yán)格意義上的 R0但課程設(shè)計(jì)報(bào)告里作為“疫情擴(kuò)散速度的近似觀察”完全夠用答辯時(shí)老師更關(guān)心你是否理解它為什么只是一個(gè)近似。4.2 SIR 模型補(bǔ)一條趨勢(shì)曲線odeint 參數(shù)與邊界SIR 模型是疫情課設(shè)的加分項(xiàng)。它把人群分成易感者 S、感染者 I、康復(fù)者 R 三組用兩個(gè)參數(shù) beta 和 gamma 描述傳播和康復(fù)速度。實(shí)現(xiàn)用 scipy 的 odeintimport numpy as np from scipy.integrate import odeint N 1400.0 beta, gamma 0.21, 0.07 I0, R0 1.0, 0.0 S0 N - I0 - R0 t np.linspace(0, 300, 300) def sir(state, t, beta, gamma): S, I, R state dSdt -beta * S * I / N dIdt beta * S * I / N - gamma * I dRdt gamma * I return dSdt, dIdt, dRdt result odeint(sir, [S0, I0, R0], t, args(beta, gamma)) S, I, R result.Tbeta 是“感染者每天有效接觸的人數(shù)”gamma 是“感染者每天康復(fù)的比例”。beta0.21、gamma0.07 時(shí)一個(gè)感染者平均傳染 3 個(gè)人、病程約 14 天模擬曲線會(huì)在大約第 60 天達(dá)到感染峰值。想調(diào)參數(shù)看效果beta 越大峰值越高越靠前gamma 越大康復(fù)越快峰值越低。這兩組參數(shù)在報(bào)告里必須寫明否則模型就是黑匣子。把模擬感染人數(shù)和真實(shí)日新增畫在同一張圖時(shí)注意量綱。模擬的 N 是 1400 萬(wàn)抽象量級(jí)真實(shí)日新增是幾百到幾萬(wàn)直接疊加是一條壓扁的線。常見的做法有兩種真實(shí)日新增除以一個(gè)縮放常數(shù)或者模擬值乘一個(gè)縮放系數(shù)。更嚴(yán)謹(jǐn)?shù)臅?huì)做參數(shù)擬合但對(duì)課程設(shè)計(jì)來說散點(diǎn)與曲線的形態(tài)對(duì)照已經(jīng)足夠表達(dá)“模型趨勢(shì) vs 現(xiàn)實(shí)趨勢(shì)”的關(guān)系。我會(huì)在代碼里注明這里做的是演示性對(duì)照不是擬合結(jié)果。import matplotlib matplotlib.use(Agg) import matplotlib.pyplot as plt plt.figure(figsize(10, 6)) plt.plot(t, I, labelSIR 模擬感染人數(shù), color#d73027) plt.scatter(real_idx, real_daily / scale_factor, s8, label真實(shí)日新增(歸一化)) plt.xlabel(Time (days)) plt.ylabel(People) plt.legend() plt.savefig(charts/sir_compare.png, dpi200)dpi200 保證截圖放進(jìn) Word 里不糊。scale_factor 需要你根據(jù)真實(shí)數(shù)據(jù)的峰值手動(dòng)調(diào)讓兩條線大致同高目的是看形態(tài)而不是精確數(shù)值。報(bào)告里一定要寫清楚“SIR 模型沒有考慮隔離政策、無(wú)癥狀感染、檢測(cè)能力變化曲線僅作趨勢(shì)示意”。這樣反而顯得你懂邊界。4.3 報(bào)告編排結(jié)論先行圖表作為證據(jù)“代碼報(bào)告.zip”里的報(bào)告比代碼難寫得多。一份能扛住答辯的報(bào)告結(jié)構(gòu)我建議按這個(gè)順序組織摘要數(shù)據(jù)源、時(shí)間范圍、清洗方式三句話說清分析對(duì)象和主要結(jié)論。數(shù)據(jù)說明字段表、保留哪些維度、如何處理缺失值寫出 daily_new 的計(jì)算口徑。圖表解讀每張圖配 1-2 句結(jié)論例如“7 月第二周起日新增開始下降結(jié)合移動(dòng)平均確認(rèn)拐點(diǎn)”。模型與局限SIR 的參數(shù)設(shè)定、為什么不能直接用模擬值放在“局限”里說透。附錄代碼清單、依賴環(huán)境、運(yùn)行順序。報(bào)告里不要貼大段代碼把關(guān)鍵統(tǒng)計(jì)量和參數(shù)放正文或表格代碼放附錄。我見過不少課設(shè)報(bào)告把 200 行代碼直接復(fù)制進(jìn)正文老師一眼掃過去就會(huì)覺得是在湊頁(yè)數(shù)。結(jié)論先行的意思是每一節(jié)第一句話就回答“這張圖說明了什么”然后再展開細(xì)節(jié)。數(shù)據(jù)分析課設(shè)的答辯時(shí)間通常很短老師看摘要就能判斷你有沒有真正跑通而不是只改了別人的圖。5. 避坑疫情課設(shè)最常見的 5 個(gè)翻車現(xiàn)場(chǎng)與排查課程設(shè)計(jì)出問題的地方往往不在分析本身而在環(huán)境、版本、編碼這些“yìn”上。下面 5 條是疫情課設(shè)里重復(fù)率最高的坑每條都是“現(xiàn)象 → 原因 → 解決”的排查邏輯。5.1 圖表里全是方塊字中文字體與編碼問題現(xiàn)象pyecharts 生成的 html 里標(biāo)題和圖例全是方塊、問號(hào)或亂碼尤其是 Windows 系統(tǒng)。原因分兩層一是數(shù)據(jù)源里的中文在讀取/導(dǎo)出時(shí)用了錯(cuò)誤編碼csv 文件里的中文變成亂碼畫圖自然亂二是 pyecharts 生成的 html 里字體棧沒聲明中文字體瀏覽器回退失敗。解決數(shù)據(jù)文件讀取時(shí)顯式指定 encoding導(dǎo)出用 encodingutf-8-sig。pyecharts 畫圖時(shí)在 TitleOpts 和 LabelOpts 里顯式設(shè)置 font_family例如 font_familyMicrosoft YaHei。如果圖表是英文數(shù)據(jù)標(biāo)題寫成中文依然可能亂碼原因就是第二種。5.2 pyecharts 版本一變老教程代碼整段不能跑現(xiàn)象網(wǎng)上抄的代碼報(bào)錯(cuò)信息是 “ImportError: cannot import name ‘Map’ from ‘pyecharts’” 或 “Timeline” 導(dǎo)入失敗。原因pyecharts 1.x 和 2.x 的 API 差異很大老教程多是 0.5.x 版本Map 的導(dǎo)入路徑完全不同。解決鎖定版本一條命令統(tǒng)一環(huán)境pip install pyecharts2.0.9導(dǎo)入方式統(tǒng)一寫成from pyecharts.charts import Map, Timeline, Line, Bar from pyecharts import options as opts這樣能避開絕大多數(shù)舊教程坑。如果用的是 Python 3.11 以上建議再確認(rèn) pyecharts 依賴的 simplejson 版本缺什么裝什么。5.3 中國(guó)地圖整塊空白省份名與地圖資源兩個(gè)坑現(xiàn)象地圖渲染出來全空白或只有個(gè)別省份有顏色。原因有兩類。第一類是省份名稱不匹配pyecharts 中國(guó)地圖內(nèi)置使用“北京”“上?!薄昂薄边@種不帶“市”“省”后綴的名稱而數(shù)據(jù)里可能寫的是“湖北省”“北京市”匹配不上就畫不出來。第二類是地圖資源沒加載新版 pyecharts 本地地圖文件需要單獨(dú)機(jī)制離線環(huán)境下 CDN 加載不到 echarts 地圖腳本整圖空白。解決名稱不匹配就用“湖北省”.replace(省, ) 這類規(guī)則清洗或者維護(hù)一個(gè)手工映射表。地圖資源加載失敗的先檢查項(xiàng)目里是否有 map js 文件沒有的話手動(dòng)把地圖 js 文件下載到本地并注冊(cè)再用 render 生成 html。這門課設(shè)的所有圖表都要能在拆了網(wǎng)的答辯教室跑起來這一點(diǎn)提前確認(rèn)。5.4 “日新增”出現(xiàn)負(fù)值diff 的副作用現(xiàn)象每日新增折線圖里突然出現(xiàn)一個(gè)向下的尖刺數(shù)值為負(fù)。原因diff() 算的是“今天的累計(jì)值減昨天的累計(jì)值”。某些數(shù)據(jù)源在某個(gè)日期修正了之前的統(tǒng)計(jì)口徑例如把之前多算的病例減回去今天的累計(jì)值反而比昨天小diff 就產(chǎn)生負(fù)值。解決在計(jì)算 daily_new 后立刻 clipchina[daily_new] china[daily_new].clip(lower0)同時(shí)報(bào)告里寫一句“負(fù)值來源于統(tǒng)計(jì)口徑修正已按 0 處理”。這樣數(shù)據(jù)說明部分反而成了加分項(xiàng)。5.5 報(bào)告里的圖表糊成一片渲染與截圖分辨率現(xiàn)象html 里圖表很清晰截圖放到 Word 后文字發(fā)虛折線邊緣鋸齒嚴(yán)重。原因普通截屏按屏幕分辨率輸出Word 顯示時(shí)進(jìn)行了縮放如果直接用 pyecharts 的 render 輸出 png默認(rèn)分辨率也不高。解決用 snapshot-selenium 組件渲染高分辨率 pngpip install snapshot-seleniumfrom pyecharts.render import make_snapshot from snapshot_selenium import snapshot make_snapshot(snapshot, charts/line_daily.html, charts/line_daily.png, pixel_ratio2)pixel_ratio2 表示按 2 倍分辨率輸出圖里文字在 Word 里放大也清晰。比手動(dòng)截圖穩(wěn)定得多。注意這 5 個(gè)坑不是互相獨(dú)立的。地圖空白時(shí)先看省份名再查資源文件日新增負(fù)值修完以后再畫圖別帶著臟數(shù)據(jù)直接可視化。6. 進(jìn)階用留出段數(shù)據(jù)自我驗(yàn)證再用 Streamlit 做成可交互看板6.1 先驗(yàn)證再交付留出三個(gè)月做回頭確認(rèn)課程設(shè)計(jì)交出去之前給自己留一道“凸出測(cè)試”只用截止到某年某月的數(shù)據(jù)清洗并畫圖之后三個(gè)月的真實(shí)數(shù)據(jù)不參與任何計(jì)算當(dāng)作未來數(shù)據(jù)來驗(yàn)證。做法很簡(jiǎn)單數(shù)據(jù)讀進(jìn)來后先按日期切一刀把后三個(gè)月單獨(dú)放一個(gè)變量train clean_df[clean_df[date] 2021-10-01] test clean_df[clean_df[date] 2021-10-01]訓(xùn)練部分觀察到的趨勢(shì)拐點(diǎn)、增長(zhǎng)率回落等結(jié)論用 test 部分的真實(shí)值去比對(duì)如果測(cè)試段的實(shí)際變化方向與基于 train 段得出的趨勢(shì)判斷一致說明分析邏輯是成立的如果明顯矛盾優(yōu)先檢查清洗是否有誤。這個(gè)過程不用寫到報(bào)告里但它能幫你避免“分析結(jié)論只是事后諸葛亮式地描述一張圖”的尷尬。6.2 十個(gè) Streamlit pyecharts 代碼把靜態(tài)報(bào)告變成可交互看板課設(shè)驗(yàn)收時(shí)如果評(píng)委可以自己選國(guó)家、拉時(shí)間范圍效果比翻 ppt 強(qiáng)很多。用 streamlit 把之前渲染 html 的代碼包一層就是一個(gè)小型可視化大屏import streamlit as st import pandas as pd from pyecharts.charts import Line from pyecharts import options as opts import streamlit.components.v1 as components st.title(疫情數(shù)據(jù)展示看板) df pd.read_csv(data/covid_clean.csv, parse_dates[date]) country st.selectbox(選擇國(guó)家或地區(qū), sorted(df[country].unique())) sub df[df[country] country].sort_values(date) line Line() line.add_xaxis(sub[date].dt.strftime(%Y-%m-%d).tolist()) line.add_yaxis(累計(jì)確診, sub[confirmed].tolist(), is_smoothTrue) line.set_global_opts( title_optsopts.TitleOpts(titlef{country} 累計(jì)確診趨勢(shì)), datazoom_opts[opts.DataZoomOpts()], ) components.html(line.render_embed(), height480, width980)selectbox 生成下拉框組件會(huì)監(jiān)聽用戶選擇并重新執(zhí)行腳本。render_embed 是 pyecharts 提供的方法把圖表 html 內(nèi)嵌到 streamlit 頁(yè)面里不需要額外生成文件。運(yùn)行方式是streamlit run app.py我第一次交這類課設(shè)時(shí)只畫了折線圖和地圖答辯老師一句話就問住了我“日新增這個(gè)數(shù)到底是你算的還是文件里給的”從那以后我養(yǎng)成了一個(gè)習(xí)慣任何數(shù)據(jù)項(xiàng)目先把口徑寫在最前面再把驗(yàn)證過程留一手寧可圖少一張也要把邏輯說到位。希望這份筆記能讓你少走幾段彎路把疫情數(shù)據(jù)課設(shè)做成一個(gè)真正能講的完整作品。本文還有配套的精品資源點(diǎn)擊獲取