Chapter 8 データ前処理

【Section 8.7に関連動画を紹介しています。】

データをインポートしたら、いざ分析だ!…と分析してみたくなります。 しかし、収集したデータはそのまま分析に進むことはできず、分析のために「前処理」する必要があります。 「データ分析は前処理が8割」とも言われます。 前処理の方法を学んでいきましょう。

データ前処理にはdplyr(読み:ディープライアール)というパッケージの関数を主に用います。 dplyrtidyverseの一部なので、tidyverseがインストールされていればOKです。

8.1 パイプ(%>%)による処理

最近はパイプ%>%を用いてデータの受け渡しを行うのが主流となっています。 パイプはmagrittrパッケージの機能ですが、tidyverseと同時にインストールされています。

まずは例を見てみましょう。

saving %>% head()
##    sav   inc size educ age black  cons
## 1   30  1920    4    2  40     1  1890
## 2  874 12403    4    9  33     0 11529
## 3  370  6396    2   17  31     0  6026
## 4 1200  7005    3    9  50     0  5805
## 5  275  6990    4   12  28     0  6715
## 6 1400  6500    4   13  33     0  5100

この結果は、前のChapterで見たhead(saving)と同じ結果です。 パイプを用いると、パイプの前のオブジェクトをパイプの後の関数の引数としてくれます。

パイプを用いた書き方は以下のとおりです。

  • 使用するオブジェクトを示す: saving
  • パイプでつなぐ: %>%
  • 使用する関数を書く: head()

別の例を見てみましょう。

saving$sav %>% mean()
## [1] 1582.51

まずデータフレームsaving内の変数sav(貯蓄)を示すオブジェクトsaving$savを書きます。 これを平均を求める関数mean()にパイプ%>%でつなぎます。 すると、貯蓄の平均を求めることができます。

ここまででは何が便利なのかわからないかもしれませんが、パイプを用いたほうがコードをわかりやすく書くことができます。

★練習問題

  • パイプを使って100の平方根を求めてください。
  • パイプを使ってsavingの変数incの中央値を求めてください。

8.2 変数の作成(及び置換)

分析の際には、収集したデータを分析しやすいように作成・置換することはよくあります。

  • 新しい変数を作成したい
  • 質問紙に逆転項目を設けていたので、変数を逆にしたい
  • 変数を標準化したい
  • 数値で入力された変数をカテゴリ変数として扱いたい
  • 連続変数をカテゴリ変数に変換したい

変数を追加・置換するdplyrの関数がmutate()です。

8.2.1 変数の新規作成

mutate()を用いて、貯蓄savを収入incで割った新しい変数「貯蓄率」saving_rateを作ってみましょう。

saving_with_rate <-
  saving %>%
    mutate(saving_rate = sav / inc)

head(saving_with_rate)
##    sav   inc size educ age black  cons saving_rate
## 1   30  1920    4    2  40     1  1890  0.01562500
## 2  874 12403    4    9  33     0 11529  0.07046682
## 3  370  6396    2   17  31     0  6026  0.05784866
## 4 1200  7005    3    9  50     0  5805  0.17130621
## 5  275  6990    4   12  28     0  6715  0.03934192
## 6 1400  6500    4   13  33     0  5100  0.21538462

1行目は2行目以降の結果を新たなデータフレームsaving_with_rateに代入するコードです。 2行目はデータフレームの指定とパイプです。savingmutate()に入れるコードです。 3行目でmutateを使っています。割り算/を使って、新しい変数saving_rateを作成しました。

head(saving_with_rate)でどのようなデータフレームになったか、先頭6行を確認しています。

なお、1行目をsavingとすると、savingが上書きされます。

★練習問題

  • savingに年齢ageを二乗した値age_squaredを加えたデータフレームを作成してください。
  • savingに収入incを円換算した値inc_yenを加えたデータフレームを作成してください。
    • 当時の為替レートは1ドル=140円程度でした。

8.2.2 逆転項目の処理

mutateを利用して、「逆転項目」の前処理をしてみましょう。 逆転項目とは、質問紙では1, 2, 3, 4, 5として聞いた数値を、データでは5, 4, 3, 2, 1として扱うものです(5件法の場合)。 以下の操作をイメージしましょう。

  • 全体にマイナスをかける→(1, 2, 3, 4, 5)が(-1, -2, -3, -4, -5)になる
  • 全体に6を足す→(-1, -2, -3, -4, -5)が(5, 4, 3, 2, 1)になる

つまり、元の変数にマイナスをかけ、6を足せば逆転項目が作成できます。

savingには逆転項目がないので、架空の数値を作成して確認してみましょう。

data <- data.frame(Q1 = c(3, 2, 4, 1, 5)) #逆転項目Q1が入ったデータフレームを作成

data_gyakuten <- 
  data %>%
    mutate(Q1_gyakuten = - Q1 + 6)

data_gyakuten
##   Q1 Q1_gyakuten
## 1  3           3
## 2  2           4
## 3  4           2
## 4  1           5
## 5  5           1

★練習問題

  • 7件法(1〜7)で収集した架空のデータフレームを作成し、逆転項目として処理してみてください。

8.2.3 変数の標準化

変数を平均0、標準偏差1の変数に変換する標準化は、変数の解釈を容易にしたり、以降の分析をしやすくするために必要です。 標準化を行う関数はscale()です。mutate()と組み合わせて、教育年数educを標準化した変数educ_standardizedを作ってみましょう。

saving_standardized_educ <-
  saving %>%
    mutate(educ_standardized = scale(educ))

head(saving_standardized_educ)
##    sav   inc size educ age black  cons educ_standardized
## 1   30  1920    4    2  40     1  1890        -2.7886549
## 2  874 12403    4    9  33     0 11529        -0.7510156
## 3  370  6396    2   17  31     0  6026         1.5777150
## 4 1200  7005    3    9  50     0  5805        -0.7510156
## 5  275  6990    4   12  28     0  6715         0.1222584
## 6 1400  6500    4   13  33     0  5100         0.4133497

★練習問題

  • 年収incを標準化した値inc_standardizedを加えたデータフレームを作成してください。

8.3 カテゴリ変数の処理

8.3.1 変数の型

Rで扱う変数には「型」と呼ばれる区別があります。 型の違いによって、今後の分析方法も変わってきます。 型を確認する方法として、オブジェクトの構造を確認する関数str()を使ってみましょう。

str(saving)
## 'data.frame':    100 obs. of  7 variables:
##  $ sav  : int  30 874 370 1200 275 1400 3159 1766 3984 1017 ...
##  $ inc  : int  1920 12403 6396 7005 6990 6500 26007 15363 14999 9185 ...
##  $ size : int  4 4 2 3 4 4 5 5 5 5 ...
##  $ educ : int  2 9 17 9 12 13 17 16 9 16 ...
##  $ age  : int  40 33 31 50 28 33 36 44 48 31 ...
##  $ black: int  1 0 0 0 0 0 0 0 1 0 ...
##  $ cons : int  1890 11529 6026 5805 6715 5100 22848 13597 11015 8168 ...
##  - attr(*, "time.stamp")= chr "25 Jun 2011 23:03"

$の右が変数名、intと書かれているのが型です。 ここではすべてintとなっていますが、これは整数(integer)を表します。 以下の型はすべて数値として扱われます。

  • int: integer, 整数
  • dbl: double, 実数
  • num: numeric, 数値

8.3.2 カテゴリ変数への変換

カテゴリ変数を表す型はfct (factor)です。savingにはカテゴリ変数がないので、カテゴリ変数を作成してみましょう。 型を変換する関数がas_xxx()です。xxxは変換したい型の名前を入れてください。 ここでは、カテゴリ変数に変換したいので、as_factor()を用います。 今はinteger型となっているblackをカテゴリ変数にしてみましょう。

saving_with_factor <-
  saving %>%
    mutate(black_factor = as_factor(black))

str(saving_with_factor)
## 'data.frame':    100 obs. of  8 variables:
##  $ sav         : int  30 874 370 1200 275 1400 3159 1766 3984 1017 ...
##  $ inc         : int  1920 12403 6396 7005 6990 6500 26007 15363 14999 9185 ...
##  $ size        : int  4 4 2 3 4 4 5 5 5 5 ...
##  $ educ        : int  2 9 17 9 12 13 17 16 9 16 ...
##  $ age         : int  40 33 31 50 28 33 36 44 48 31 ...
##  $ black       : int  1 0 0 0 0 0 0 0 1 0 ...
##  $ cons        : int  1890 11529 6026 5805 6715 5100 22848 13597 11015 8168 ...
##  $ black_factor: Factor w/ 2 levels "0","1": 2 1 1 1 1 1 1 1 2 1 ...
##  - attr(*, "time.stamp")= chr "25 Jun 2011 23:03"

ここでは、mutateを使って、新たな変数black_factorを作成してみました。 str()を使って、型がFactorになったことが確認できます。

カテゴリ変数として扱いたい変数はすべてas_factorを使ってカテゴリ変数にしておきましょう。

また、文字列型(chr, character)の変数はこのままでは分析に使用できないので、必ずas_factorを実行しておきましょう。

★練習問題

  • 家族人数sizeをカテゴリ変数に変換したデータフレームを作成してください。

8.3.3 ダミー変数の作成

ある変数から、別のダミー変数を作成したいことはよくあります。 ここでは、教育年数のデータを12年を基準に「高卒以上」「高卒未満」の2つに区分してみましょう。 2つの場合分けの際には、if_else関数を使うと便利です。 if_else()if_else(条件, 条件が成りたつ場合の値, 条件が成り立たない場合の値)と書いて使用します。

table(saving$educ) #教育年数の度数分布
## 
##  2  3  4  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 
##  1  1  1  1  4 10 11  9  4 32  2  4  1  9  6  2  1  1
saving_with_hsdummy <-
  saving %>%
    mutate(highschool = if_else(educ >= 12, 1, 0))

head(saving_with_hsdummy)
##    sav   inc size educ age black  cons highschool
## 1   30  1920    4    2  40     1  1890          0
## 2  874 12403    4    9  33     0 11529          0
## 3  370  6396    2   17  31     0  6026          1
## 4 1200  7005    3    9  50     0  5805          0
## 5  275  6990    4   12  28     0  6715          1
## 6 1400  6500    4   13  33     0  5100          1
table(saving_with_hsdummy$highschool) #作成したダミー変数の度数分布
## 
##  0  1 
## 42 58

highschoolという教育年数が12年以上であれば1、教育年数が12年未満であれば0を示すダミー変数を作成することができました。 なお、ここで作成した変数は連続変数として扱われているので、必要に応じてas_factor()も行っておきましょう。

saving_with_hsdummy <-
  saving %>%
    mutate(highschool = if_else(educ >= 12, 1, 0),
           highschool = as_factor(highschool)) #highschoolをfactor型として上書き

head(saving_with_hsdummy)
##    sav   inc size educ age black  cons highschool
## 1   30  1920    4    2  40     1  1890          0
## 2  874 12403    4    9  33     0 11529          0
## 3  370  6396    2   17  31     0  6026          1
## 4 1200  7005    3    9  50     0  5805          0
## 5  275  6990    4   12  28     0  6715          1
## 6 1400  6500    4   13  33     0  5100          1

★練習問題

  • 「年齢が40代以上」を表すダミー変数over40を加えたデータフレームを作成してください。

8.3.4 カテゴリ変数の作成

2つのカテゴリにしたい場合は上記のif_elseが良いですが、3つ以上にしたい場合はcase_whenが便利です。 例えば年齢ageを年代別のカテゴリ変数にしてみましょう。 case_whencase_when(条件A ~ 条件が成り立つ場合の値, 条件B ~ 条件が成り立つ場合の値...と書いていきます。

summary(saving$age) #年齢の記述統計の確認
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   26.00   33.00   38.50   38.77   44.00   54.00
saving_with_age_category <-
  saving %>%
    mutate(age_category = case_when(age < 30 ~ "20s",
                                    age >= 30 & age < 40 ~ "30s",
                                    age >= 40 & age < 50 ~ "40s",
                                    age >= 50 ~ "50s"
                                    )
          )

head(saving_with_age_category)
##    sav   inc size educ age black  cons age_category
## 1   30  1920    4    2  40     1  1890          40s
## 2  874 12403    4    9  33     0 11529          30s
## 3  370  6396    2   17  31     0  6026          30s
## 4 1200  7005    3    9  50     0  5805          50s
## 5  275  6990    4   12  28     0  6715          20s
## 6 1400  6500    4   13  33     0  5100          30s

少し長くなってしまいましたが、年齢の条件別に年代別の文字列を割り当てました。 ここで生成した変数はchr(character)型になっているので、分析に使う場合はas_factorを行っておきましょう。

★練習問題

  • 年収6000ドル未満を“poor”、年収6000ドル以上12000ドル未満を“middle”、 年収12000ドル以上を“rich”、とするカテゴリ変数inc_categoryを追加したデータフレームを作成しなさい。

8.4 変数の選択

インポートしたデータの中に不要な変数が含まれていたり、前処理の結果不要になった変数が出てくることはよくあります。 dplyrの関数select()を用いると、データフレームの変数を選択したり、削除したりすることができます。 まずはsavingから収入incと年齢ageを取り出してみましょう。

saving_selected <-
  saving %>%
    select(inc, age)

head(saving_selected)
##     inc age
## 1  1920  40
## 2 12403  33
## 3  6396  31
## 4  7005  50
## 5  6990  28
## 6  6500  33

2つの変数のみのデータフレームになりました。

ハイフン-を使うと、該当する変数を削除し、残りの変数はそのままとすることができます。 savingから消費consを取り除いてみましょう。

saving_deleted <-
  saving %>%
    select(-cons)

head(saving_deleted)
##    sav   inc size educ age black
## 1   30  1920    4    2  40     1
## 2  874 12403    4    9  33     0
## 3  370  6396    2   17  31     0
## 4 1200  7005    3    9  50     0
## 5  275  6990    4   12  28     0
## 6 1400  6500    4   13  33     0

★練習問題

  • 貯蓄sav、家族の人数size、黒人ダミーblackの3変数のデータフレームを作成してください。
  • 教育年数educ、年齢ageを取り除いたデータを作成してください。

8.5 変数の並び替え

データを確認する際に、ある変数をもとに並べ替えたい場合があります。 データを並べ替えるdplyrの関数がarrange()です。 ここでは、savingを収入incで並び替えてみましょう。

saving_arranged <-
  saving %>%
    arrange(inc)

head(saving_arranged)
##    sav  inc size educ age black cons
## 1    0  750    2    4  49     0  750
## 2   30 1920    4    2  40     1 1890
## 3   50 2340    2    6  46     1 2290
## 4 -112 2936    7   10  39     0 3048
## 5 2575 3941    4    9  34     0 1366
## 6 2483 4091    6    8  44     0 1608

値が小さいものが上、値が大きいものが下となる昇順で並び替えられます。 逆に降順にしたい場合は、desc()を利用します。

saving_arranged_desc <-
  saving %>%
    arrange(desc(inc))

head(saving_arranged_desc)
##     sav   inc size educ age black  cons
## 1  1800 32080    2   16  54     0 30280
## 2 10668 30996    4   12  41     0 20328
## 3  4115 30610    4   16  44     0 26495
## 4  3159 26007    5   17  36     0 22848
## 5 -2749 24226    5   17  44     0 26975
## 6  5082 19362    3   11  48     0 14280

8.6 すべての作業をパイプでつなげる

これまで行ってきた一連の作業は、すべてパイプ%>%でつなげることができます。 パイプでつなげることで作業の流れがわかりやすくなり、不要なオブジェクトを生成する必要もなくなります。 ここでは、以下の作業をまとめて行ってみましょう。

  • 貯蓄率saving_rateの作成
  • 家族人数sizeの削除
  • 収入incで並び替え(降順)
saving_handled <-
  saving %>%
    mutate(saving_rate = sav / inc) %>%
    select(-size) %>%
    arrange(desc(inc))

head(saving_handled)
##     sav   inc educ age black  cons saving_rate
## 1  1800 32080   16  54     0 30280  0.05610973
## 2 10668 30996   12  41     0 20328  0.34417344
## 3  4115 30610   16  44     0 26495  0.13443319
## 4  3159 26007   17  36     0 22848  0.12146730
## 5 -2749 24226   17  44     0 26975 -0.11347313
## 6  5082 19362   11  48     0 14280  0.26247289

コードが長くなるため、適宜#を使ってコメントを加えておくと良いでしょう。

saving_handled
  saving %>%
    mutate(saving_rate = sav / inc) %>% #貯蓄率の作成
    select(-size) %>% #家族人数の削除
    arrange(desc(inc)) #収入で並び替え(高いものが上)

8.7 関連動画