気ままにデータ分析

データサイエンティスト見習いの学習メモ

tidyverseを駆使してRでコロナウィルス患者数の推移を棒グラフにしてみた

最近Rを触っていなかったので、復習がてら。
東洋経済のコロナ情報ページがバズっていたので、同じように日本のコロナウイルス患者数の推移のグラフを作ってみようかなと思いました。
グラフを作成した以外のことはやってません。悪しからず。
toyokeizai.net


tidyverseのパッケージ群を使ってデータ前処理から可視化までやってみました。
github.com


使用したデータ

github.com

データはこちらから引っ張ってきました。ジョンズ・ホプキンズ大学が公開しているようです。

国別・地域別の感染者数、回復者数、死亡者数のデータがcsvで取得できます。

また時系列ごとのデータと日ごとのデータにも分かれています。

厚生労働省や各社メディアによる発表の数とは異なっている場合があります。

データ取得

library(tidyverse)
library(lubridate)

#累計患者数
time_series_confermed <- read_csv('~/time_series_19-covid-Confirmed.csv')
#累計死亡者数
time_series_deaths <- read_csv('~/time_series_19-covid-Deaths.csv')
#累計回復者数
time_series_recovered <- read_csv('~/time_series_19-covid-Recovered.csv')

データ前処理


取得したデータをみてみましょう。

time_series_confermed
# A tibble: 442 x 57
   `Province/State` `Country/Region`    Lat   Long `1/22/20` `1/23/20` `1/24/20`
   <chr>            <chr>             <dbl>  <dbl>     <dbl>     <dbl>     <dbl>
 1 NA               Thailand          15     101           2         3         5
 2 NA               Japan             36     138           2         1         2
 3 NA               Singapore          1.28  104.          0         1         3
 4 NA               Nepal             28.2    84.2         0         0         0
 5 NA               Malaysia           2.5   112.          0         0         0
 6 British Columbia Canada            49.3  -123.          0         0         0
 7 New South Wales  Australia        -33.9   151.          0         0         0
 8 Victoria         Australia        -37.8   145.          0         0         0
 9 Queensland       Australia        -28.0   153.          0         0         0
10 NA               Cambodia          11.6   105.          0         0         0
# … with 432 more rows, and 50 more variables: `1/25/20` <dbl>, `1/26/20` <dbl>,
#   `1/27/20` <dbl>, `1/28/20` <dbl>, `1/29/20` <dbl>, `1/30/20` <dbl>,
#   `1/31/20` <dbl>, `2/1/20` <dbl>, `2/2/20` <dbl>, `2/3/20` <dbl>, `2/4/20` <dbl>,
#   `2/5/20` <dbl>, `2/6/20` <dbl>, `2/7/20` <dbl>, `2/8/20` <dbl>, `2/9/20` <dbl>,
#   `2/10/20` <dbl>, `2/11/20` <dbl>, `2/12/20` <dbl>, `2/13/20` <dbl>,
#   `2/14/20` <dbl>, `2/15/20` <dbl>, `2/16/20` <dbl>, `2/17/20` <dbl>,
#   `2/18/20` <dbl>, `2/19/20` <dbl>, `2/20/20` <dbl>, `2/21/20` <dbl>,
#   `2/22/20` <dbl>, `2/23/20` <dbl>, `2/24/20` <dbl>, `2/25/20` <dbl>,
#   `2/26/20` <dbl>, `2/27/20` <dbl>, `2/28/20` <dbl>, `2/29/20` <dbl>, `3/1/20` <dbl>,
#   `3/2/20` <dbl>, `3/3/20` <dbl>, `3/4/20` <dbl>, `3/5/20` <dbl>, `3/6/20` <dbl>,
#   `3/7/20` <dbl>, `3/8/20` <dbl>, `3/9/20` <dbl>, `3/10/20` <dbl>, `3/11/20` <dbl>,
#   `3/12/20` <dbl>, `3/13/20` <dbl>, `3/14/20` <dbl>

日付が列になっていて横長のデータになっています。tidyではありませんね。
これを縦長のデータに変換します。まずは累計患者数に絞ってデータを整形していきます。

confirmed <- time_series_confermed %>% 
  filter(`Country/Region`==('Japan')) %>%  #日本に絞る
  select(-Lat, -Long,-`Province/State`) %>%  #不必要な列を除外
  pivot_longer(c(-`Country/Region`), names_to = "日付", values_to = "累計患者数") 

今まで縦長⇔横長の変換はgather()/spread()でやってました。
存在は知っていましたが、恥ずかしながらpivot_longer()/pivot_wider()をまともに使ったのは今回が初めてでした(爆)
なにこれ超便利じゃん。。

confirmed
# A tibble: 53 x 3
   `Country/Region` 日付    累計患者数
   <chr>            <chr>        <dbl>
 1 Japan            1/22/20          2
 2 Japan            1/23/20          1
 3 Japan            1/24/20          2
 4 Japan            1/25/20          2
 5 Japan            1/26/20          4
 6 Japan            1/27/20          4
 7 Japan            1/28/20          7
 8 Japan            1/29/20          7
 9 Japan            1/30/20         11
10 Japan            1/31/20         15

縦長のデータになりました。


次に可視化のために日付データの処理をします。

confirmed$日付 <- mdy(confirmed$日付)
confirmed$日付 <- as.Date(confirmed$日付)

#明らかに患者数がおかしいデータがあったので、正しいデータに修正
confirmed <- confirmed %>% 
  mutate(累計患者数 = case_when(日付=='2020-01-23'~ 2, 日付!='2020-02-06'~累計患者数)) %>% 
  mutate(累計患者数 = case_when(日付=='2020-02-06'~ 25, 日付!='2020-02-06'~累計患者数))

累計患者数のみの棒グラフ


それではまずは累計患者数のみで棒グラフを描いてみます。

confirmed %>% 
  ggplot(aes(日付, 累計患者数))+
  ggtitle('新型コロナウイルス患者数の推移(日本)') +
  scale_x_date(date_breaks = '5 days', date_labels = '%m/%d') +
  theme(axis.text.x = element_text(angle=30, hjust=1)) +
  geom_bar(stat = 'identity', fill='#fff494')+
  theme_dark(base_family = "HiraKakuPro-W3")

f:id:Yupine:20200316003921p:plain
こんなグラフができました。
次は、累計回復者数と累計死亡者数のデータも加えて積み上げ棒グラフを作ります。

前処理と結合


累計患者数の時と同様に整形をしてjoinします。

#累計回復者数
recovered <- time_series_recovered %>% 
  filter(`Country/Region`==('Japan')) %>% 
  select(-Lat, -Long,-`Province/State`) %>% 
  pivot_longer(c(-`Country/Region`), names_to = "日付", values_to = "累計回復者数")
recovered$日付 <- mdy(recovered$日付)
recovered$日付 <- as.Date(recovered$日付)

#累計死亡者数
deaths <- time_series_deaths %>% 
  filter(`Country/Region`==('Japan')) %>% 
  select(-Lat, -Long,-`Province/State`) %>% 
  pivot_longer(c(-`Country/Region`), names_to = "日付", values_to = "累計死亡者数") 
deaths$日付 <- mdy(deaths$日付)
deaths$日付 <- as.Date(deaths$日付)

#累計患者数、累計回復者数、累計死亡者数をジョイン
japan_covid <- confirmed %>% 
  left_join(select(recovered, "日付", "累計回復者数"), by = "日付") %>% 
  left_join(select(deaths, "日付","累計死亡者数"), by = "日付") 


1つのデータフレームにまとまりました。

japan_covid
# A tibble: 53 x 5
   `Country/Region` 日付       累計患者数 累計回復者数 累計死亡者数
   <chr>            <date>          <dbl>        <dbl>        <dbl>
 1 Japan            2020-01-22          2            0            0
 2 Japan            2020-01-23          2            0            0
 3 Japan            2020-01-24          2            0            0
 4 Japan            2020-01-25          2            0            0
 5 Japan            2020-01-26          4            1            0
 6 Japan            2020-01-27          4            1            0
 7 Japan            2020-01-28          7            1            0
 8 Japan            2020-01-29          7            1            0
 9 Japan            2020-01-30         11            1            0
10 Japan            2020-01-31         15            1            0

積み上げ棒グラフの描画のためにさらに縦長のデータにします。

japan_covid <- japan_covid %>%
  pivot_longer(c(-`Country/Region`,-日付), names_to = "カテゴリ", values_to = "人数")
japan_covid
# A tibble: 159 x 4
   `Country/Region` 日付       カテゴリ      人数
   <chr>            <date>     <chr>        <dbl>
 1 Japan            2020-01-22 累計患者数       2
 2 Japan            2020-01-22 累計回復者数     0
 3 Japan            2020-01-22 累計死亡者数     0
 4 Japan            2020-01-23 累計患者数       2
 5 Japan            2020-01-23 累計回復者数     0
 6 Japan            2020-01-23 累計死亡者数     0
 7 Japan            2020-01-24 累計患者数       2
 8 Japan            2020-01-24 累計回復者数     0
 9 Japan            2020-01-24 累計死亡者数     0
10 Japan            2020-01-25 累計患者数       2
# … with 149 more rows

積み上げ棒グラフの描画

それでは描画してみましょう。

japan_covid %>% 
  ggplot(aes(x=日付,y=人数,fill=factor(カテゴリ)))+
  ggtitle('新型コロナウィルス患者数の推移(日本)')+
  geom_bar(stat = 'identity', position = position_identity())+
  scale_x_date(date_breaks = '5 days', date_labels = '%m/%d') +
  scale_fill_manual(values = c(累計患者数 = "#fff494", 累計回復者数 = "#00fa9a",累計死亡者数="#ff6347"),
                    limits=c("累計患者数","累計回復者数","累計死亡者数"))+
  theme_dark(base_family = "HiraKakuPro-W3")+
  theme(legend.position = c(0.2,0.8),
        axis.text.x = element_text(angle=30, hjust=1),
        plot.title = element_text(face = "bold")) +
  guides(fill=guide_legend(title = NULL))

f:id:Yupine:20200316010032p:plain
欲しかったグラフができました。(元々のデータが間違っているところがあるので100%正確ではないが)

やっぱりグラフの描画に関してはPythonよりRの方がやりやすいし好きな気がするなあ。。
tidyverse神。Hadley Wickham様神。

次の記事ではPythonで同じことをやってみたいと思います。