【R】データの取り込み＆クリーニング

この記事のコードをまとめたものは[Github](https://github.com/FruitGranola/R_Data_Cleaning)にあります。

# モチベーション

[恩師 HP ](https://www.asanoucla.com/)の[このページ](http://www.ner.takushoku-u.ac.jp/masano/class_material/waseda/keiryo/2_data_frame.html)についての自分用メモです。
より詳しく何をしているか補足を入れ、コードを簡潔にするように心がけた。

正直、データクリーニングってアイディア勝負なところあるよね。

# 使用するデータ

[Freedom House の HP](https://freedomhouse.org/)
[Freedom House のオープンソース（Excel）](https://freedomhouse.org/sites/default/files/2020-02/2020_Country_and_Territory_Ratings_and_Statuses_FIW1973-2020.xlsx)

今回は Freedom House から提供されている「Country and Territory Ratings and Statuses」
（筆者アクセス日 : 2021/1/15）を使用する。

# 使用するパッケージ

```{r}
library(tidyverse) # RStudio を使うなら一番最初に読み込むパッケージ
library(magrittr) # パイプ処理用のパッケージ
library(readxl) # 今回使用するファイル形式が Excel のため、このパッケージを使用する
```



# データの取り込み

今回は Excel ファイルをダウンロードしてきて、そのまま使用する。
ちなみに、余裕があるなら用事のあるシートだけを CSV ファイルに変換したほうが良いかも...

`sheet = 2` : 使用するシートは 2 つ目と指定する。
`skip = 2` : 上から 2 列目までを無視する。
`na = "-"` : "-" を na に置き換える。

```{r}
FH <- read_excel("Data/2020_Country_and_Territory_Ratings_and_Statuses_FIW1973-2020.xlsx", sheet = 2, skip = 2, na = "-")
```
# データクリーニング

ここからデータの中身を確認して、データを整理していく。

## 各変数の class を確認＆修正

...1 : character
PR...n : numeric
CL...n : numeric
Status...n : character
であればOK

`str()` で各変数の class を確認してみる。

```{r}
str(FH)
```
```:出力結果
## tibble [205 x 142] (S3: tbl_df/tbl/data.frame)
##  $ ...1        : chr [1:205] "Afghanistan" "Albania" "Algeria" "Andorra" ...
##  $ PR...2      : chr [1:205] "4" "7" "6" "4" ...
##  $ CL...3      : chr [1:205] "5" "7" "6" "3" ...
##  $ Status...4  : chr [1:205] "PF" "NF" "NF" "PF" ...
##  $ PR...5      : num [1:205] 7 7 6 4 NA NA 2 NA 1 1 ...
##  $ CL...6      : num [1:205] 6 7 6 4 NA NA 2 NA 1 1 ...
##  $ Status...7  : chr [1:205] "NF" "NF" "NF" "PF" ...
##  $ PR...8      : num [1:205] 7 7 6 4 NA NA 2 NA 1 1 ...
##  $ CL...9      : num [1:205] 6 7 6 4 NA NA 4 NA 1 1 ...
##  $ Status...10 : chr [1:205] "NF" "NF" "NF" "PF" ...
##  $ PR...11     : num [1:205] 7 7 7 4 6 NA 2 NA 1 1 ...
##  $ CL...12     : num [1:205] 6 7 6 4 6 NA 4 NA 1 1 ...
##  $ Status...13 : chr [1:205] "NF" "NF" "NF" "PF" ...
##  $ PR...14     : num [1:205] 7 7 6 4 6 NA 6 NA 1 1 ...
##  $ CL...15     : num [1:205] 6 7 6 4 6 NA 5 NA 1 1 ...
##  $ Status...16 : chr [1:205] "NF" "NF" "NF" "PF" ...
##  $ PR...17     : num [1:205] 6 7 6 NA 7 NA 6 NA 1 1 ...
##  $ CL...18     : num [1:205] 6 7 6 NA 7 NA 6 NA 1 1 ...
##  $ Status...19 : chr [1:205] "NF" "NF" "NF" NA ...
##  $ PR...20     : num [1:205] 7 7 6 NA 7 NA 6 NA 1 1 ...
##  $ CL...21     : num [1:205] 7 7 6 NA 7 NA 5 NA 1 1 ...
##  $ Status...22 : chr [1:205] "NF" "NF" "NF" NA ...
##  $ PR...23     : num [1:205] 7 7 6 NA 7 NA 6 NA 1 1 ...
##  $ CL...24     : num [1:205] 7 7 6 NA 7 NA 5 NA 1 1 ...
##  $ Status...25 : chr [1:205] "NF" "NF" "NF" NA ...
##  $ PR...26     : num [1:205] 7 7 6 NA 7 NA 6 NA 1 1 ...
##  $ CL...27     : num [1:205] 7 7 6 NA 7 NA 5 NA 1 1 ...
##  $ Status...28 : chr [1:205] "NF" "NF" "NF" NA ...
##  $ PR...29     : num [1:205] 7 7 6 NA 7 2 6 NA 1 1 ...
##  $ CL...30     : num [1:205] 7 7 6 NA 7 2 5 NA 1 1 ...
##  $ Status...31 : chr [1:205] "NF" "NF" "NF" NA ...
##  $ PR...32     : num [1:205] 7 7 6 NA 7 2 3 NA 1 1 ...
##  $ CL...33     : num [1:205] 7 7 6 NA 7 3 3 NA 1 1 ...
##  $ Status...34 : chr [1:205] "NF" "NF" "NF" NA ...
##  $ PR...35     : num [1:205] 7 7 6 NA 7 2 2 NA 1 1 ...
##  $ CL...36     : num [1:205] 7 7 6 NA 7 3 2 NA 1 1 ...
##  $ Status...37 : chr [1:205] "NF" "NF" "NF" NA ...
##  $ PR...38     : num [1:205] 7 7 6 NA 7 2 2 NA 1 1 ...
##  $ CL...39     : num [1:205] 7 7 6 NA 7 3 2 NA 1 1 ...
##  $ Status...40 : chr [1:205] "NF" "NF" "NF" NA ...
##  $ PR...41     : num [1:205] 7 7 6 NA 7 2 2 NA 1 1 ...
##  $ CL...42     : num [1:205] 7 7 6 NA 7 3 1 NA 1 1 ...
##  $ Status...43 : chr [1:205] "NF" "NF" "NF" NA ...
##  $ PR...44     : num [1:205] 7 7 6 NA 7 2 2 NA 1 1 ...
##  $ CL...45     : num [1:205] 7 7 6 NA 7 3 1 NA 1 1 ...
##  $ Status...46 : chr [1:205] "NF" "NF" "NF" NA ...
##  $ PR...47     : num [1:205] 6 7 5 NA 7 2 2 NA 1 1 ...
##  $ CL...48     : num [1:205] 6 7 6 NA 7 3 1 NA 1 1 ...
##  $ Status...49 : chr [1:205] "NF" "NF" "NF" NA ...
##  $ PR...50     : num [1:205] 7 7 6 NA 7 2 1 NA 1 1 ...
##  $ CL...51     : num [1:205] 7 7 4 NA 7 3 2 NA 1 1 ...
##  $ Status...52 : chr [1:205] "NF" "NF" "PF" NA ...
##  $ PR...53     : num [1:205] 7 7 4 NA 7 3 1 NA 1 1 ...
##  $ CL...54     : num [1:205] 7 6 4 NA 7 2 3 NA 1 1 ...
##  $ Status...55 : chr [1:205] "NF" "NF" "PF" NA ...
##  $ PR...56     : num [1:205] 7 4 4 NA 6 3 1 5 1 1 ...
##  $ CL...57     : num [1:205] 7 4 4 NA 4 3 3 5 1 1 ...
##  $ Status...58 : chr [1:205] "NF" "PF" "PF" NA ...
##  $ PR...59     : num [1:205] 6 4 7 NA 6 3 2 4 1 1 ...
##  $ CL...60     : num [1:205] 6 3 6 NA 6 3 3 3 1 1 ...
##  $ Status...61 : chr [1:205] "NF" "PF" "NF" NA ...
##  $ PR...62     : num [1:205] 7 2 7 2 7 4 2 3 1 1 ...
##  $ CL...63     : num [1:205] 7 4 6 1 7 3 3 4 1 1 ...
##  $ Status...64 : chr [1:205] "NF" "PF" "NF" "F" ...
##  $ PR...65     : num [1:205] 7 3 7 1 7 4 2 3 1 1 ...
##  $ CL...66     : num [1:205] 7 4 7 1 7 3 3 4 1 1 ...
##  $ Status...67 : chr [1:205] "NF" "PF" "NF" "F" ...
##  $ PR...68     : num [1:205] 7 3 6 1 6 4 2 4 1 1 ...
##  $ CL...69     : num [1:205] 7 4 6 1 6 3 3 4 1 1 ...
##  $ Status...70 : chr [1:205] "NF" "PF" "NF" "F" ...
##  $ PR...71     : num [1:205] 7 4 6 1 6 4 2 5 1 1 ...
##  $ CL...72     : num [1:205] 7 4 6 1 6 3 3 4 1 1 ...
##  $ Status...73 : chr [1:205] "NF" "PF" "NF" "F" ...
##  $ PR...74     : num [1:205] 7 4 6 1 6 4 2 5 1 1 ...
##  $ CL...75     : num [1:205] 7 4 6 1 6 3 3 4 1 1 ...
##  $ Status...76 : chr [1:205] "NF" "PF" "NF" "F" ...
##  $ PR...77     : num [1:205] 7 4 6 1 6 4 3 4 1 1 ...
##  $ CL...78     : num [1:205] 7 5 5 1 6 3 3 4 1 1 ...
##  $ Status...79 : chr [1:205] "NF" "PF" "NF" "F" ...
##  $ PR...80     : num [1:205] 7 4 6 1 6 4 2 4 1 1 ...
##  $ CL...81     : num [1:205] 7 5 5 1 6 3 3 4 1 1 ...
##  $ Status...82 : chr [1:205] "NF" "PF" "NF" "F" ...
##  $ PR...83     : num [1:205] 7 4 6 1 6 4 1 4 1 1 ...
##  $ CL...84     : num [1:205] 7 5 5 1 6 2 2 4 1 1 ...
##  $ Status...85 : chr [1:205] "NF" "PF" "NF" "F" ...
##  $ PR...86     : num [1:205] 7 3 6 1 6 4 3 4 1 1 ...
##  $ CL...87     : num [1:205] 7 4 5 1 6 2 3 4 1 1 ...
##  $ Status...88 : chr [1:205] "NF" "PF" "NF" "F" ...
##  $ PR...89     : num [1:205] 6 3 6 1 6 4 3 4 1 1 ...
##  $ CL...90     : num [1:205] 6 3 5 1 5 2 3 4 1 1 ...
##  $ Status...91 : chr [1:205] "NF" "PF" "NF" "F" ...
##  $ PR...92     : num [1:205] 6 3 6 1 6 4 2 4 1 1 ...
##  $ CL...93     : num [1:205] 6 3 5 1 5 2 2 4 1 1 ...
##  $ Status...94 : chr [1:205] "NF" "PF" "NF" "F" ...
##  $ PR...95     : num [1:205] 5 3 6 1 6 2 2 5 1 1 ...
##  $ CL...96     : num [1:205] 6 3 5 1 5 2 2 4 1 1 ...
##  $ Status...97 : chr [1:205] "NF" "PF" "NF" "F" ...
##  $ PR...98     : num [1:205] 5 3 6 1 6 2 2 5 1 1 ...
##  $ CL...99     : num [1:205] 5 3 5 1 5 2 2 4 1 1 ...
##   [list output truncated]
```

PR...2 と CL...3 は numeric であるはずが character になっている。
`unique()` で変数の値を確認してみる。

```{r}
FH$PR...2 %>% unique()
```
```:出力結果
## [1] "4"    "7"    "6"    NA     "1"    "2"    "5"    "3"    "2(5)"
```
```{r}
FH$CL...3 %>% unique()
```
```:出力結果
## [1] "5"    "7"    "6"    "3"    NA     "1"    "4"    "2"    "3(6)"
```

どうやら "2(5)" や "3(6)" のような数値でないものが混ざっているみたいだ。
これを `if_elese()` で NA に置き換える。その後、`as.numeric()` で character から numeric に変数の class を変換する。
ついでに、...1 は国名なので、変数名を country に変えておく

```{r}
FH %<>% 
  mutate(PR...2 = if_else(PR...2 == "2(5)", "NA", PR...2),
         CL...3 = if_else(CL...3 == "3(6)", "NA", CL...3)) %>% 
  mutate(across(c(PR...2, CL...3), as.numeric)) %>%  # 2 つの列に同時に as.numeric を施す
  rename(country = 1)                                # 1 という変数名を country に変更
```

# wide 形式を long 形式に変形する

このデータは wide と呼ばれる形式のため、tidy な R 生活を送っている人にとって非常に使いにくい。
これを long と呼ばれる形式に変形する。

# wide の状態で行う処理

まずは"いじりたくない変数"と"いじりたい変数"で分割する。

```{r}
FH_country <- FH %>% select(country) # いじりたくない変数

FH_value <- FH %>% select(-country) # いじりたい変数
```

いじりたい変数である FH_value の変数名に年数を付けていく。
pr_xxxx という感じにしたい。そのため、まずは stringr パッケージ（tidyverse に内包されている）の関数を使う。

```{r}
colnames(FH_value) <-                       # 変数名に代入する
  str_replace_all(colnames(FH_value),       # 変数名の
                  c("\\.\\.\\." = "_")) %>% # 「...」を「_」に置き換える  
  str_subset("PR|CL|Status") %>%            # PR, CL, Statusと名の付く変数を対象とする
  str_replace_all(c("[0-9]" = "",           # 数字を消す
                    "PR" = "pr",            # 小文字に変更  
                    "CL" = "cl",            # 小文字に変更 
                    "Status" = "st")) %>%   # 小文字に変更
  str_c(.,  rep(setdiff(1972:2019, 1981),   # 変数名の後ろに1972~2019までの数字を付ける。あと、1981を飛ばす
                each = 3))                  # 1年につき、3つの変数があるので、3回同じ数字を付けて、次の年に行くようにする

FH_value %>% names()
```
```:出力結果
##   [1] "pr_1972" "cl_1972" "st_1972" "pr_1973" "cl_1973" "st_1973" "pr_1974"
##   [8] "cl_1974" "st_1974" "pr_1975" "cl_1975" "st_1975" "pr_1976" "cl_1976"
##  [15] "st_1976" "pr_1977" "cl_1977" "st_1977" "pr_1978" "cl_1978" "st_1978"
##  [22] "pr_1979" "cl_1979" "st_1979" "pr_1980" "cl_1980" "st_1980" "pr_1982"
##  [29] "cl_1982" "st_1982" "pr_1983" "cl_1983" "st_1983" "pr_1984" "cl_1984"
##  [36] "st_1984" "pr_1985" "cl_1985" "st_1985" "pr_1986" "cl_1986" "st_1986"
##  [43] "pr_1987" "cl_1987" "st_1987" "pr_1988" "cl_1988" "st_1988" "pr_1989"
##  [50] "cl_1989" "st_1989" "pr_1990" "cl_1990" "st_1990" "pr_1991" "cl_1991"
##  [57] "st_1991" "pr_1992" "cl_1992" "st_1992" "pr_1993" "cl_1993" "st_1993"
##  [64] "pr_1994" "cl_1994" "st_1994" "pr_1995" "cl_1995" "st_1995" "pr_1996"
##  [71] "cl_1996" "st_1996" "pr_1997" "cl_1997" "st_1997" "pr_1998" "cl_1998"
##  [78] "st_1998" "pr_1999" "cl_1999" "st_1999" "pr_2000" "cl_2000" "st_2000"
##  [85] "pr_2001" "cl_2001" "st_2001" "pr_2002" "cl_2002" "st_2002" "pr_2003"
##  [92] "cl_2003" "st_2003" "pr_2004" "cl_2004" "st_2004" "pr_2005" "cl_2005"
##  [99] "st_2005" "pr_2006" "cl_2006" "st_2006" "pr_2007" "cl_2007" "st_2007"
## [106] "pr_2008" "cl_2008" "st_2008" "pr_2009" "cl_2009" "st_2009" "pr_2010"
## [113] "cl_2010" "st_2010" "pr_2011" "cl_2011" "st_2011" "pr_2012" "cl_2012"
## [120] "st_2012" "pr_2013" "cl_2013" "st_2013" "pr_2014" "cl_2014" "st_2014"
## [127] "pr_2015" "cl_2015" "st_2015" "pr_2016" "cl_2016" "st_2016" "pr_2017"
## [134] "cl_2017" "st_2017" "pr_2018" "cl_2018" "st_2018" "pr_2019" "cl_2019"
## [141] "st_2019"
```

変数名を変更し終わったら、`bind_cols()`で国名とがっちゃんこする。

```{r}
FH_wide <- bind_cols(FH_country, FH_value)
```

# long に変形する

ここでも、2 回に分けて wide から long に変形する。

まずは pr と cl を type という変数にまとめ、wide から long に変形させる。

```{r}
PR_CL_long <- FH_wide %>% 
  select(country,                         # country と
         starts_with(c("pr", "cl"))) %>%  # pr と cl で初まる変数だけを選ぶ  
  pivot_longer(pr_1972:cl_2019,           # 変換したい変数の範囲を指定
               names_to = "type",         # 「変数名(pr_1972 など)を type に入れる
               values_to = "value") %>%   # 「変数(pr_1972 など) の値」を value に入れる
  separate(type,
           into = c("type", "year"),      # type の中身を type と year 二つの変数に分ける  
           sep = "_") %>%                 # type の中身は pr_1973 のように "_" で分けられている
           drop_na()                      # 欠損値を省く

PR_CL_long %>% head()
```
```:出力結果
## # A tibble: 6 x 4
##   country     type  year  value
##   <chr>       <chr> <chr> <dbl>
## 1 Afghanistan pr    1972      4
## 2 Afghanistan pr    1973      7
## 3 Afghanistan pr    1974      7
## 4 Afghanistan pr    1975      7
## 5 Afghanistan pr    1976      7
## 6 Afghanistan pr    1977      6
```

つぎに st を status という変数にし、wide から long に変形させる。

```{r}
ST_long <- FH_wide %>% 
  select(country,                        # country と
         starts_with("st")) %>%          # st で初まる変数だけを選ぶ
  pivot_longer(st_1972:st_2019,          # 変換したい変数の範囲を指定
               names_to = "name",        # 「変数名(st_1972など)をnameに入れる
               values_to = "status") %>% # 「変数(st_1972など) の値」をstatusに入れる
  separate(name, 
           into = c("name", "year"),     # nameの中身(st_1972など）をnameとyear 二つの変数に分ける
           sep = "_") %>%                # nameの中身はst_1972のように "_" で分けられている
  select(-name)%>%                       # nameは不要なので削除  
  drop_na()                              # 欠損値を省く

ST_long %>% head()
```
```:出力結果
## # A tibble: 6 x 3
##   country     year  status
##   <chr>       <chr> <chr> 
## 1 Afghanistan 1972  PF    
## 2 Afghanistan 1973  NF    
## 3 Afghanistan 1974  NF    
## 4 Afghanistan 1975  NF    
## 5 Afghanistan 1976  NF    
## 6 Afghanistan 1977  NF
```
wide に変形させた 2 個のデータを `left_join()` でがっちゃんこする。
そして、完成した long 形式のデータを見てみよう。

```{r}
FH_long <- left_join(PR_CL_long, ST_long, by = c("country", "year"))　
# by = c("country", "year") は何を目印にがっちゃんこするかを示す

rmarkdown::paged_table(FH_long) # 完成品を見てみよう
```

`rmarkdown::paged_table()` はこんな感じで出力される。👇

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1025774/94cc34a4-00e0-c0ed-5697-a0e1719a18b1.png)