最初,沒有人在意這場災難,這不過是一場山火,一次旱災,一個物種的滅絕,一座城市的消失,直到這場災難和每個人息息相關。
——《流浪地球》
2020年註定是讓人難忘的一年,一場「前所未有」的新冠肺炎疫情打亂了所有人的日常生活,每日上升的確診數讓人們陷入恐慌。但有時候,持續滾動的數字往往會讓人從最初的恐懼變成麻木,因此筆者今天會用Python把一個一個冰冷的數字變成一幅一幅生動的圖片,帶你更加具體的了解世界疫情。
通過本文,你會學到如何用Python做數據分析,數據可視化,畫世界疫情地圖,了解世界疫情。本次用到的數據我在前面文章分享過,具體見全球抗「疫」:各國疫情數據早知道。
下面我會詳細介紹如何使用這些數據,建議本文代碼在Jupyter notebook上運行,話不多說,Let『s go!
首先當然是導入必備的幾個包了
import pandas as pdimport numpy as np然後就是導入數據,本次使用的數據是Github上一個項目裡的,也可以直接用pandas包導入,需要注意的是不能直接使用Github那個網址,否則會報錯,需要將前面部分改成https://raw.githubusercontent.com/,然後就是加入數據的目錄地址。數據主要是是三個文件,包含了疫情的確診數(confirmed),治癒數(recoved),死亡數(deaths),基本上每日會更新最新疫情數據。confirmed = pd.read_csv('https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_19-covid-Confirmed.csv')recovered = pd.read_csv('https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_19-covid-Recovered.csv')deaths = pd.read_csv('https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_19-covid-Deaths.csv')數據已經導入了,讓我們來看看數據是啥樣的吧。head(5)是查看數據前五行;confirmed表裡面包含發生疫情的國家,經緯度,以及從2020年1月22日至今的每日的確診數;recovered表則記錄了治癒數;deaths表則記錄了死亡數。使用shape則可以列印出三個數據表的維度。每個都是(101,40)維,即101行,40列。print(confirmed.shape)print(recovered.shape)print(deaths.shape)前面我們已經搞清楚了數據,下面就是我們的正餐—數據可視化。這部分主要用到matplotlib這個繪圖包,至於繪製地圖,放在第三部分講。import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['SimHei'] #用來正常顯示中文標籤plt.rcParams['axes.unicode_minus'] = False #用來正常顯示負號首先看看在我們的數據中,哪些地區發生了疫情。可以看出一共49個地區都有新冠肺炎病例。countries = confirmed['Country/Region'].unique()print(countries)接下來看看世界疫情發展趨勢,我們的數據還需要再整理下,要計算出每日所有地區新冠肺炎的確診數,治癒數,死亡數。all_confirmed = np.sum(confirmed.iloc[:,4:])all_recovered = np.sum(recovered.iloc[:,4:])all_deaths = np.sum(deaths.iloc[:,4:])plt.plot(all_confirmed,color = 'red',label = '確診',marker = 'o')plt.plot(all_recovered,color = 'blue',label = '治癒',marker = 'o')plt.plot(all_deaths,color = 'lime',label = '死亡',marker = 'o')plt.xticks(rotation = 45,size = 10)plt.yticks(size=20)plt.xlabel('時 間',size = 20)plt.ylabel('數 目',size = 20)plt.title('全球疫情變化趨勢',size = 30)plt.legend(loc = "upper left",fontsize = 20)plt.show()可以看出,目前新冠肺炎確診病例還在持續增加,不過令人高興的是治癒數也在持續增長,死亡數很少,希望疫情拐點早日出現,疫情早日結束。下面看看新冠肺炎的死亡率,首先計算死亡率數據,然後就可以直接畫圖。death_rate = (all_deaths/all_confirmed)*100plt.plot(death_rate,color = 'lime',label = '死亡',marker = 'o')plt.xticks(rotation = 45,size = 10)plt.yticks(size = 15)plt.xlabel('時 間',size = 20)plt.ylabel('死亡率',size = 20)plt.title('全球疫情死亡率',size = 30)由於本次疫情主要發生在中國大陸,下面來具體研究下中國大陸的疫情情況,首先從全部數據中提取出中國大陸的數據。裡面包含了省份,以及每個省最新的確診數,治癒數,死亡數。last_update = '2/26/20' # 設置最新數據日期China_cases = confirmed[['Province/State',last_update]][confirmed['Country/Region'] == 'Mainland China']China_cases['recovered']=recovered[[last_update]][recovered['Country/Region']=='Mainland China']China_cases['deaths']=deaths[[last_update]][deaths['Country/Region']=='Mainland China']China_cases = China_cases.set_index('Province/State')China_cases = China_cases.rename(columns = {last_update:'confirmed'})Mainland_china = China_cases.sort_values(by='confirmed',ascending=True)Mainland_china.plot(kind='barh', figsize=(20,30), color = ['red','blue','lime'], width=1, rot=2)plt.title('中國大陸各省市疫情數量', size=30)plt.ylabel('省/市',size=20)plt.xlabel('數量',size = 20)plt.yticks(size=20)plt.xticks(size=15)plt.legend(bbox_to_anchor=(0.95,0.95),fontsize = 20)可以看到,湖北省三項數據高居第一位,且遠遠高於其他省份。下面看看中國大陸的治癒率和死亡率數據,數據使用下面的代碼即可計算出來,最終結果在recover_rate和death_rate裡。confirmed_china = confirmed[confirmed['Country/Region']=='Mainland China']confirmed_china = np.sum(confirmed_china.iloc[:,4:])recovered_china = recovered[recovered['Country/Region'] == 'Mainland China']recovered_china = np.sum(recovered_china.iloc[:,4:])deaths_china = deaths[deaths['Country/Region'] == 'Mainland China']deaths_china = np.sum(deaths_china.iloc[:,4:])recover_rate = (recovered_china/confirmed_china)*100death_rate = (deaths_china/confirmed_china)*100plt.plot(recover_rate, color = 'blue', label = '治癒率', marker = 'o')plt.plot(death_rate, color = 'lime', label = '死亡率', marker = 'o')plt.title('中國大陸治癒率 VS 死亡率',size=30)plt.ylabel('數量',size=20)plt.xlabel('時間',size=20)plt.xticks(rotation=45,size=10)plt.yticks(size=15)plt.legend(loc = "upper left",fontsize = 20)雖然在1月25日-1月31日期間死亡率略高於治癒率,但其他時間段,治癒率遠遠高於死亡率,這都得益於全國廣大醫務人員的不懈努力!那中國大陸其他地區這一情況咋樣呢?代碼大同小異,我們一起來看看,首先還是提取出其他地區的數據。confirmed_others = confirmed[confirmed['Country/Region'] != 'Mainland China']confirmed_others = np.sum(confirmed_others.iloc[:,4:])recovered_others = recovered[recovered['Country/Region'] != 'Mainland China']recovered_others = np.sum(recovered_others.iloc[:,4:])deaths_others = deaths[deaths['Country/Region'] != 'Mainland China']deaths_others = np.sum(deaths_others.iloc[:,4:])recover_rate = (recovered_others/confirmed_others)*100death_rate = (deaths_others/confirmed_others)*100plt.plot(recover_rate, color = 'blue', label = '治癒率', marker = 'o')plt.plot(death_rate, color = 'lime', label = '死亡率', marker = 'o')plt.title('其他地區治癒率 VS 死亡率',size=30)plt.ylabel('數量',size=20)plt.xlabel('時間',size=20)plt.xticks(rotation=45,size=10)plt.yticks(size=15)plt.legend(loc = "upper left",fontsize = 20)接下來看看其他地區疫情數量。首先還是提出其他地區的數據others = confirmed[['Country/Region',last_update]][confirmed['Country/Region'] != 'Mainland China']others['recovered'] = recovered[[last_update]][recovered['Country/Region'] != 'Mainland China']others['death'] = deaths[[last_update]][deaths['Country/Region'] != 'Mainland China']others_countries = others.rename(columns = {last_update:'confirmed'})others_countries = others_countries.set_index('Country/Region')others_countries = others_countries.groupby('Country/Region').sum()others_countries.sort_values(by = 'confirmed',ascending = True).plot(kind='barh', figsize=(20,30), color = ['red','blue','lime'], width=1, rot=2)plt.title('世界其他地區疫情數量', size=30)plt.ylabel('Country/Region',size = 20)plt.xlabel('數量',size = 20)plt.yticks(size=10)plt.xticks(size=15)plt.legend(bbox_to_anchor=(0.95,0.95),fontsize = 20)從圖可以看到,韓國,義大利,日本這些地區也有很多新冠肺炎患者。想必看到這,大家已經厭煩了前面的折線圖,柱狀圖了,下面筆者將教大家如何畫出疫情地圖,將每個數據對應到地圖上聽起來是不是很好玩呢?這裡主要用到兩個python包,一個是folium包,這個包也是筆者最近才發現的繪圖包,類似於R語言繪圖裡的ggplot2,可以添加圖層來定義一個Map對象,最後以幾種方式將Map對象展現出來。這裡有一個詳細教程,感興趣的可以看看https://python-visualization.github.io/folium/。另一個包就是plotly了,這也是一個強大的繪圖包,詳細教程請看這裡https://plot.ly/python/plotly-express/。首先是folium包繪製地圖,import folium,只需要導入包就可以了,沒下載這個包的記得下載才能使用。我們在前面數據裡加入中國大陸的數據,並使用武漢的經緯度。others=confirmed[['Country/Region','Lat','Long',last_update]][confirmed['Country/Region'] != 'Mainland China']others['recovered'] = recovered[[last_update]][recovered['Country/Region'] != 'Mainland China']others['death'] = deaths[[last_update]][deaths['Country/Region'] != 'Mainland China']others_countries = others.rename(columns = {last_update:'confirmed'})others_countries.loc['94'] = ['Mainland China',30.9756,112.2707,confirmed_china[-1],recovered_china[-1],deaths_china[-1]]world_map = folium.Map(location=[10, -20], zoom_start=2.3,tiles='Stamen Toner')上面一行是定義一個world_map對象;location的格式為[緯度,經度];zoom_start表示初始地圖的縮放尺寸,數值越大放大程度越大;tiles為地圖類型,用於控制繪圖調用的地圖樣式,默認為'OpenStreetMap',也有一些其他的內建地圖樣式,如'Stamen Terrain'、'Stamen Toner'、'Mapbox Bright'、'Mapbox Control Room'等;也可以傳入'None'來繪製一個沒有風格的樸素地圖,或傳入一個URL來使用其它的自選osm。然後往world_map裡添加其他元素,注意這裡的for循環和最後的add_to是把經緯度點的信息一個一個的加進去for lat, lon, value, name in zip(others_countries['Lat'], others_countries['Long'], others_countries['confirmed'], others_countries['Country/Region']): folium.CircleMarker([lat, lon], radius=10, popup = ('<strong>Country</strong>: ' + str(name).capitalize() + '<br>' '<strong>Confirmed Cases</strong>: ' + str(value) + '<br>'), color='red', fill_color='red', fill_opacity=0.7 ).add_to(world_mappopup:str型或folium.Popup()對象輸入,用於控制標記部件的具體樣式(folium內部自建了許多樣式),默認為None,即不顯示部件。代碼使用的是自定義的網頁樣式,其中<strong>表示加粗,<br>表示換行,以便將各個數據顯示出來。然後再運行world_map,即可出現下面的地圖樣式,這是一種可交互的地圖,可以隨意移動縮放,滑鼠點擊地圖上紅點,即可出現地區的疫情信息。下面我再教大家用plotly繪製每日疫情擴散地圖,首先是導入包import plotly.express as px在這裡,我想繪製每日疫情擴散地圖,我需要增加一列,裡面記錄了每天的日期,因此我們的數據還需要再重新整理下,這裡需要用的melt函數,它將列名轉換為列數據(columns name → column values),重構DataFrame,confirmed = confirmed.melt(id_vars = ['Province/State', 'Country/Region', 'Lat', 'Long'], var_name='date',value_name = 'confirmed')# value_vars:需要轉換的列名,如果剩下的列全部都要轉換,就不用寫了。# var_name和value_name是自定義設置對應的列名。重新得到的數據如下,新增了date一列,記錄時間。還需要把date列轉換成datetime格式的數據confirmed['date_dt'] = pd.to_datetime(confirmed.date, format="%m/%d/%y")confirmed.date = confirmed.date_dt.dt.dateconfirmed.rename(columns={'Country/Region': 'country', 'Province/State': 'province'}, inplace=True)recovered = recovered.melt(id_vars = ['Province/State', 'Country/Region', 'Lat', 'Long'], var_name='date',value_name = 'recovered')recovered['date_dt'] = pd.to_datetime(recovered.date, format="%m/%d/%y")recovered.date = recovered.date_dt.dt.daterecovered.rename(columns={'Country/Region': 'country', 'Province/State': 'province'}, inplace=True)deaths = deaths.melt(id_vars = ['Province/State', 'Country/Region', 'Lat', 'Long'], var_name='date', value_name = 'deaths')deaths['date_dt'] = pd.to_datetime(deaths.date, format="%m/%d/%y")deaths.date = deaths.date_dt.dt.datedeaths.rename(columns={'Country/Region': 'country', 'Province/State': 'province'}, inplace=True)現在三種數據都有了,我們把它們合併在一張表裡面,主要用到merge函數merge_on = ['province', 'country', 'date']all_date = confirmed.merge(deaths[merge_on + ['deaths']], how='left', on=merge_on). \ merge(recovered[merge_on + ['recovered']], how='left', on=merge_on)由於要演示的是疫情擴散地圖,因此筆者用實心圓來表示每個地區的疫情變化,而實心圓的大小則代表了三種數據的大小,所以在我們的數據裡要加一列,使用confirmed數據的二分之一次方來表示實心圓的大小。Coronavirus_map = all_data.groupby(['date_dt', 'province'])['confirmed', 'deaths','recovered', 'Lat', 'Long'].max().reset_index()Coronavirus_map['size'] = Coronavirus_map.confirmed.pow(0.5) Coronavirus_map['date_dt'] = Coronavirus_map['date_dt'].dt.strftime('%Y-%m-%d')最後就是繪圖部分,代碼也很簡單,如果有不懂得參數可以使用help(px.scatter_geo)來查看每個參數用法fig = px.scatter_geo(Coronavirus_map, lat='Lat', lon='Long', scope='asia', color="size", size='size', hover_name='province', hover_data=['confirmed', 'deaths', 'recovered'], projection="natural earth",animation_frame="date_dt",title='亞洲地區疫情擴散圖')fig.update(layout_coloraxis_showscale=False)fig.show()好了地圖部分就畫好了,代碼運行玩就會出現下面的樣式,點擊播放按鈕,就會動態變化下面是動態演示,展示了從2020-01-21至2020-02-26的疫情擴散情況。好了,本文到這裡就結束了,希望這次疫情也能早早結束,中國加油!人類加油!
━━━━━━━━━━━━━━━━━━━━
文字來源|木子偉
圖片來源|木子偉
推文編輯|宋欣蕊
推文審核|木子偉
歡迎投稿至:Datahelpclub@126.com
━━━━━━━━━━━━━━━━━━━━
文章好看在這裡