實(shí)戰(zhàn):用 Pandas 完成 COVID-19 疫情建模與論文共現(xiàn)分析)
Data-Science-For-Beginners 課 07 作業(yè)實(shí)戰(zhàn)用 Pandas 完成 COVID-19 疫情建模與論文共現(xiàn)分析【免費(fèi)下載鏈接】Data-Science-For-Beginners10 Weeks, 20 Lessons, Data Science for All!項(xiàng)目地址: https://gitcode.com/GitHub_Trending/da/Data-Science-For-Beginners本篇實(shí)戰(zhàn)指南以本倉庫 2-Working-With-Data/07-python/assignment.md 的課后作業(yè)為骨架面向已經(jīng)學(xué)完 Python 與 Pandas 課程 的讀者。你將基于課內(nèi)兩個(gè)挑戰(zhàn)COVID-19 疫情傳播建模、COVID-19 學(xué)術(shù)論文文本分析中已寫好的代碼繼續(xù)深化完成多國R_t對(duì)比、死亡/康復(fù)與感染的相關(guān)性、病程時(shí)長推斷、死亡率時(shí)序變化以及藥物共現(xiàn)矩陣、熱力圖與正則提取劑量的實(shí)戰(zhàn)任務(wù)。讀完本文你將掌握用 Pandas Matplotlib 處理時(shí)間序列與半結(jié)構(gòu)化文本的完整套路并學(xué)會(huì)把課內(nèi)示例代碼改造成可復(fù)用的分析管線。作業(yè)背景與完成標(biāo)準(zhǔn)本作業(yè)要求你在課內(nèi)兩個(gè)挑戰(zhàn)的基礎(chǔ)上接著寫而不是從零開始。挑戰(zhàn)代碼分別在 notebook-covidspread.ipynb疫情建模與 notebook-papers.ipynb論文分析中。評(píng)分標(biāo)準(zhǔn)Rubric分三檔等級(jí)要求優(yōu)秀Exemplary所有任務(wù)完成有圖形化展示與文字解釋且至少完成兩個(gè)加分目標(biāo)之一合格Adequate完成超過 5 項(xiàng)任務(wù)但未嘗試加分目標(biāo)或結(jié)果不清晰需改進(jìn)Needs Improvement完成少于 5 項(xiàng)但多于 3 項(xiàng)且可視化無法說明問題從評(píng)分標(biāo)準(zhǔn)可以看出任務(wù)數(shù)量、可視化質(zhì)量、解釋說明缺一不可加分目標(biāo)是拉開差距的關(guān)鍵。作業(yè)原始數(shù)據(jù)說明與評(píng)分細(xì)則詳見 translations/bg/2-Working-With-Data/07-python/assignment.md保加利亞語譯本內(nèi)容與英文原版一致。第一部分COVID-19 疫情傳播建模準(zhǔn)備數(shù)據(jù)與課內(nèi)代碼回顧疫情數(shù)據(jù)來自約翰霍普金斯大學(xué) CSSE 的時(shí)間序列數(shù)據(jù)集本倉庫在 data/COVID/ 下提供了三份快照倉庫內(nèi)共 266 行、150 列覆蓋 188 個(gè)國家/地區(qū)日期列從 2020-01-22 起time_series_covid19_confirmed_global.csv累計(jì)確診time_series_covid19_recovered_global.csv累計(jì)康復(fù)time_series_covid19_deaths_global.csv累計(jì)死亡notebook 中默認(rèn)從網(wǎng)絡(luò)讀取離線時(shí)可改用本地快照只需替換base_url見 notebook-covidspread.ipynb 第 3 個(gè)代碼單元base_url ../../data/COVID/ # 離線模式改用倉庫本地快照 # base_url https://raw.githubusercontent.com/... # 在線模式默認(rèn) infected pd.read_csv(base_url time_series_covid19_confirmed_global.csv) recovered pd.read_csv(base_url time_series_covid19_recovered_global.csv) deaths pd.read_csv(base_url time_series_covid19_deaths_global.csv)課內(nèi)已經(jīng)完成的預(yù)處理鏈路包括按Country/Region用groupby().sum()合并省份行 → 用drop(columns[Lat,Long,Province/State])去掉元數(shù)據(jù)列 → 用mkframe(country)把三份累計(jì)數(shù)據(jù)拼成按日期索引的 DataFrame → 用diff()求每日新增、rolling(7).mean()平滑周波動(dòng)。此外人口數(shù)據(jù)來自 data/UID_ISO_FIPS_LookUp_Table.csv用于計(jì)算每百萬人感染率pinfected。R_t的核心公式8 天滑動(dòng)窗口在 notebook 中實(shí)現(xiàn)為df[Rt] df[ninfected].rolling(8).apply(lambda x: x[4:].sum()/x[:4].sum())其數(shù)學(xué)含義是第t天的基本再生數(shù)近似等于窗口內(nèi)后半段新增感染數(shù)之和除以前半段之和即R_t (I_{t-7}I_{t-6}I_{t-5}I_{t-4}) / (I_{t-3}I_{t-2}I_{t-1}I_t)其中I_t為第t天新增感染人數(shù)。R_t 1表示疫情仍在擴(kuò)散R_t 1表示傳播在收斂。畫圖前需把除零產(chǎn)生的inf替換為NaN再用fillna(methodpad)前向填充否則曲線會(huì)出現(xiàn)斷口ax df[df.index 2020-05-01][Rt].replace(np.inf, np.nan).fillna(methodpad).plot(figsize(10,3)) ax.set_ylim([0,6]) # 限制縱軸以看清早期波動(dòng) ax.axhline(1, linestyle--, colorred) # R_t1 參考線 plt.show()任務(wù)一多國 R_t 對(duì)比圖把課內(nèi)的單國邏輯封裝成函數(shù)返回某國的R_t序列再對(duì) 56 個(gè)國家統(tǒng)一繪圖def compute_rt(country, window8, half4): df mkframe(country) df[ninfected] df[infected].diff() rt df[ninfected].rolling(window).apply( lambda x: x[half:].sum()/x[:half].sum(), rawTrue) return rt.replace(np.inf, np.nan).fillna(methodpad) countries [US, United Kingdom, Italy, Brazil, India, Japan] rt_series {c: compute_rt(c) for c in countries} # 方案 A單圖疊加比較 ax pd.DataFrame(rt_series).plot(figsize(12, 4)) ax.set_ylabel(R_t); ax.axhline(1, linestyle--, colorred) # 方案 B并排多子圖適合各國波峰錯(cuò)峰明顯的場(chǎng)景 fig, axes plt.subplots(2, 3, figsize(12, 6), shareyTrue) for ax, c in zip(axes.flat, countries): rt_series[c].plot(axax, titlec) ax.axhline(1, linestyle--, colorred, lw0.8) plt.tight_layout()實(shí)現(xiàn)要點(diǎn)rawTrue讓apply直接傳入 ndarray 而非 Series可顯著加速滑動(dòng)窗口計(jì)算各國疫情階段不同疊加圖適合看誰先起峰、誰先收斂子圖適合逐國觀察R_t是否持續(xù)高于 1。任務(wù)二死亡數(shù)、康復(fù)數(shù)與感染數(shù)的相關(guān)性用mkframe拿到累計(jì)值后直接調(diào)用 Pandas 內(nèi)置的相關(guān)系數(shù)并結(jié)合散點(diǎn)圖觀察滯后關(guān)系df mkframe(US) corr df[[infected, recovered, deaths]].corr() print(corr) # 平滑后更能反映趨勢(shì)相關(guān)性 smooth df[[infected, recovered, deaths]].rolling(7).mean() smooth.plot.scatter(xinfected, ydeaths)可以預(yù)期感染數(shù)與死亡數(shù)高度正相關(guān)但死亡往往滯后于感染若干天存在病程時(shí)滯。一個(gè)值得探索的分析是計(jì)算每日新增死亡與每日新增感染在不同時(shí)間滯后 k 天下的相關(guān)系數(shù)找出相關(guān)系數(shù)最大時(shí)的 k這為任務(wù)三的病程推斷提供定量依據(jù)new_inf df[infected].diff().rolling(7).mean() new_deaths df[deaths].diff().rolling(7).mean() lags {} for k in range(0, 40): lags[k] new_deaths.corr(new_inf.shift(k)) best_k max(lags, keylags.get)任務(wù)三推斷典型病程時(shí)長思路是以視覺方式關(guān)聯(lián)感染率與死亡率曲線并尋找異常。把兩條曲線放到同一張圖上觀察死亡曲線相對(duì)感染曲線的時(shí)間偏移df[ninfected] df[infected].diff().rolling(7).mean() df[ndeaths] df[deaths].diff().rolling(7).mean() # 歸一化到 [0,1] 便于疊加比較形狀 ax (df[ninfected]/df[ninfected].max()).plot(labelnew infected (norm)) (df[ndeaths]/df[ndeaths].max()).shift(0).plot(axax, labelnew deaths (norm)) ax.legend()實(shí)際操作上可以遍歷滯后天數(shù) k把ndeaths.shift(k)與ninfected疊加找到兩條曲線峰對(duì)峰最吻合的 k即為粗略病程時(shí)長。注意不同國家因檢測(cè)策略、死亡報(bào)告口徑不同推斷出的滯后可能不一致這正是作業(yè)要求多看幾個(gè)國家的原因——異常點(diǎn)如某國死亡率曲線突然偏離往往對(duì)應(yīng)數(shù)據(jù)質(zhì)量或政策干預(yù)如封城、檢測(cè)量變化事件。任務(wù)四死亡率及其隨時(shí)間的變化基本定義fatality rate deaths / infected * 100。作業(yè)的提示非常關(guān)鍵要考慮病程天數(shù)先平移一條時(shí)間序列再做計(jì)算。原因在于當(dāng)天確診的人不會(huì)當(dāng)天死亡直接用同日累計(jì)值會(huì)低估早期真實(shí)病死率df mkframe(US) df[fatality] df[deaths] / df[infected] * 100 df[fatality].plot() # 樸素計(jì)算早期明顯偏低 # 平移改進(jìn)假設(shè)病程 D 天將感染序列后移 D 天再相除 D 14 # 可由任務(wù)三得到的滯后天數(shù)替換 df[fatality_shifted] df[deaths].shift(-D) / df[infected] * 100 df[[fatality, fatality_shifted]].plot()同時(shí)建議平滑rolling(7).mean()去除報(bào)告導(dǎo)致的周波動(dòng)并觀察死亡率隨時(shí)間是否趨穩(wěn)——這能反映醫(yī)療資源擠兌、治療手段改進(jìn)或檢測(cè)范圍擴(kuò)大等動(dòng)態(tài)因素。第二部分COVID-19 論文分析數(shù)據(jù)集說明與課內(nèi)代碼回顧本挑戰(zhàn)使用 CORD-19 論文數(shù)據(jù)集倉庫不隨附需自行下載metadata.csv大小約 1 GB。課內(nèi) notebook notebook-papers.ipynb 已完成如下分析鏈路讀取metadata.csv把publish_time轉(zhuǎn)成datetime并畫直方圖手工維護(hù)藥物清單medicationshydroxychloroquine、chloroquine、tocilizumab、remdesivir、azithromycin、lopinavir、ritonavir、dexamethasone、heparin、favipiravir、methylprednisolone與診斷清單diagnosiscovid、sars、pneumonia、infection、diabetes、coronavirus、death用df[m] df[abstract].apply(lambda x: str(x).lower().count( m))逐詞計(jì)數(shù)注意詞首加空格避免chloroquine被hydroxychloroquine內(nèi)的子串污染按年-月分組groupby([index.year, index.month]).sum()得到治療策略月度趨勢(shì)用np.zeros((len(medications), len(diagnosis)))構(gòu)建藥物×診斷共現(xiàn)矩陣逐篇摘要累加用plt.imshow(..., cmaphot)畫熱力圖并用 Plotly 的go.Sankey畫桑基圖notebook 中封裝為sankey(cat1, cat2, m, treshold0, h1[], h2[])函數(shù)。任務(wù)一構(gòu)建藥物共現(xiàn)矩陣把課內(nèi)藥物×診斷的代碼改造成藥物×藥物遍歷每篇摘要只要某兩種藥物在同一摘要中出現(xiàn)就計(jì)數(shù)一次meds medications # 沿用課內(nèi) 11 種藥物清單 coocc np.zeros((len(meds), len(meds)), dtypeint) for a in df[abstract]: x str(a).lower() present [m for m in meds if m in x] for i in range(len(present)): for j in range(i1, len(present)): coocc[meds.index(present[i]), meds.index(present[j])] 1 coocc[meds.index(present[j]), meds.index(present[i])] 1 # 對(duì)稱 cooc_df pd.DataFrame(coocc, indexmeds, columnsmeds)出于效率考慮也可以先構(gòu)造布爾矩陣再與自身轉(zhuǎn)置做矩陣乘法present pd.DataFrame({m: df[abstract].str.contains( m, caseFalse) for m in meds})然后coocc present.T present注意此時(shí)對(duì)角線為各藥物總出現(xiàn)次數(shù)。觀察重點(diǎn)哪些藥物常在同一篇論文里成對(duì)出現(xiàn)例如 chloroquine 與 azithromycin、lopinavir 與 ritonavir 常作為聯(lián)合用藥方案被共同研究。任務(wù)二熱力圖可視化共現(xiàn)矩陣用 Matplotlib 畫出共現(xiàn)矩陣熱力圖fig, ax plt.subplots(figsize(8, 6)) im ax.imshow(coocc, interpolationnearest, cmaphot) ax.set_xticks(range(len(meds))); ax.set_xticklabels(meds, rotation90) ax.set_yticks(range(len(meds))); ax.set_yticklabels(meds) plt.colorbar(im, axax) plt.show()熱力圖中亮色格高共現(xiàn)次數(shù)即聯(lián)合用藥研究熱點(diǎn)。若矩陣數(shù)值跨度大可先取np.log1p(coocc)再畫壓低少數(shù)極高值對(duì)色標(biāo)的壓縮效應(yīng)也可疊加數(shù)值標(biāo)注ax.text(j, i, coocc[i,j])提升可讀性。注意課內(nèi)藥物×診斷熱力圖樣式covidtreat.png 為治療策略堆疊面積圖熱力圖繪制邏輯見 notebook 第 26 個(gè)代碼單元可直接遷移復(fù)用。加分目標(biāo)一chord 弦圖可視化共現(xiàn)作業(yè)推薦的第三方庫是chordPyPI 包名。用法示意from chord import Chord # 傳入對(duì)稱矩陣與標(biāo)簽列表矩陣元素為整數(shù)頻次 Chord(coocc.tolist(), meds).to_html() # 生成可交互 HTML若coocc數(shù)值過大可先二值化或按閾值截?cái)嘀槐A艄铂F(xiàn)次數(shù)高于閾值的藥物對(duì)否則弦圖會(huì)過于擁擠。按任務(wù)說明此目標(biāo)與另一加分目標(biāo)完成其一即可達(dá)到優(yōu)秀檔。加分目標(biāo)二用正則表達(dá)式提取藥物劑量從take 400mg of chloroquine daily這類句子中抽取劑量如400mg并用 DataFrame 匯總每種藥物出現(xiàn)過的劑量及次數(shù)。關(guān)鍵技巧在藥物名周圍限定上下文窗口只統(tǒng)計(jì)與藥物名文本距離很近的數(shù)值import re from collections import defaultdict def extract_doses(abstracts, medicine, window30): doses defaultdict(int) pat re.compile(r(\d(?:\.\d)?\s*(?:mg|g|mcg|microgram|gram|milligram)), re.I) for a in abstracts: a str(a).lower() for mm in re.finditer(re.escape(medicine), a): start max(0, mm.start() - window) end min(len(a), mm.end() window) ctx a[start:end] for dm in pat.finditer(ctx): doses[dm.group(1).lower()] 1 return doses rows [] for med in medications: for dose, cnt in extract_doses(df[abstract], med).items(): rows.append({medication: med, dose: dose, count: cnt}) dose_df pd.DataFrame(rows).sort_values([medication, count], ascending[True, False])要點(diǎn)re.escape(medicine)避免藥物名中的特殊字符被當(dāng)作正則元字符窗口大小此處 30 字符決定文本鄰近的判定范圍劑量模式\d(?:\.\d)?\s*(?:mg|g|...)覆蓋整數(shù)/小數(shù)與常見單位??蛇M(jìn)一步做單位歸一化如把0.4 g與400 mg視為同一劑量并觀察同一藥物不同劑量隨時(shí)間/國別的分布差異。倉庫內(nèi)可深入閱讀的資料課程正文2-Working-With-Data/07-python/README.mdSeries/DataFrame 核心操作、apply/groupby/rolling用法疫情建模完整代碼notebook-covidspread.ipynb論文分析完整代碼notebook-papers.ipynb疫情本地?cái)?shù)據(jù)data/COVID/三份累計(jì)時(shí)間序列 CSV人口數(shù)據(jù)data/UID_ISO_FIPS_LookUp_Table.csv作業(yè)英文原版2-Working-With-Data/07-python/assignment.md疫情趨勢(shì)圖covidspread.png治療策略趨勢(shì)圖covidtreat.png課程配套 R 語言版本2-Working-With-Data/07-python/R/供對(duì)照學(xué)習(xí)完成建議按先復(fù)現(xiàn)、后改造、再獨(dú)立的順序推進(jìn)先在兩個(gè) notebook 中逐單元運(yùn)行確認(rèn)基線輸出再基于本文給出的函數(shù)模板完成四項(xiàng)建模任務(wù)與兩項(xiàng)論文分析任務(wù)最后任選一個(gè)加分目標(biāo)沖刺優(yōu)秀檔??梢暬瘎?wù)必配上文字結(jié)論例如某國R_t在何時(shí)跌破 1某兩種藥物共現(xiàn)次數(shù)顯著高于其他組合這既是評(píng)分標(biāo)準(zhǔn)Exemplary 要求graphically illustrated and explained的要求也是數(shù)據(jù)科學(xué)報(bào)告的基本素養(yǎng)。【免費(fèi)下載鏈接】Data-Science-For-Beginners10 Weeks, 20 Lessons, Data Science for All!項(xiàng)目地址: https://gitcode.com/GitHub_Trending/da/Data-Science-For-Beginners創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考