1
1

More than 3 years have passed since last update.

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

Last updated at Posted at 2021-01-16

この記事のコードをまとめたものはGithubにあります。

モチベーション

恩師 HP このページについての自分用メモです。
より詳しく何をしているか補足を入れ、コードを簡潔にするように心がけた。

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

使用するデータ

Freedom House の HP
Freedom House のオープンソース(Excel)

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

使用するパッケージ

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

データの取り込み

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

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

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 を確認してみる。

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() で変数の値を確認してみる。

FH$PR...2 %>% unique()
出力結果
## [1] "4"    "7"    "6"    NA     "1"    "2"    "5"    "3"    "2(5)"
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 に変えておく

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 の状態で行う処理

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

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

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

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

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()で国名とがっちゃんこする。

FH_wide <- bind_cols(FH_country, FH_value)

long に変形する

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

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

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 に変形させる。

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 形式のデータを見てみよう。

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

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1