Chapter 6 データハンドリング

6.1 繰り返し・条件分岐

6.1.1 繰り返し構文

データを加工する際,変更箇所の少ない演算を何度も繰り返し行うことがあります. そんなときに便利なのがforを使った繰り返し構文です.

for(i in 範囲){
  コマンド 1
  コマンド 2
  コマンド 3
}

ここで,iは繰り返しを制御する文字です.「i範囲内の値を順番に取ったときに~というコマンドを実行する」という指令を出しています.例を見てみましょう.No.1からNo.10を出力したいときには次のようなコードで実行できます.文字を出力したいときはcat()関数が便利です.引数は出力したい文字です."\n"で改行を指定します.

for(i in 1:10){
  cat("No.", i, "\n") # No. i を出力して改行
}
## No. 1 
## No. 2 
## No. 3 
## No. 4 
## No. 5 
## No. 6 
## No. 7 
## No. 8 
## No. 9 
## No. 10

6.1.1.1 Tips: 空箱をつくる

繰り返し構文で出力したデータを1つにまとめて保存したい場合,予め「空箱」を作っておくと便利です.

## 空箱を作る ##
numbers <- rep(NA, 10) # NA 10個からなるベクトル

## 繰り返し ##
for(i in 1:10){
  numbers[i] <- paste(i) # ベクトルnumbers の第i成分にiを代入
}

## 中身を確認 ##
numbers
##  [1] "1"  "2"  "3"  "4"  "5"  "6"  "7"  "8"  "9"  "10"

ここで,rep()はリピートを表す関数です.上の例では欠損NA10個からなるベクトルを生成しています.

6.1.2 条件分岐

条件分岐もデータハンドリングでよく使われる構文です.ifの直後の()には何らかの条件をいれ,真TRUEであれば{}内のコマンドが実行され,偽FALSEであれば{}内のコマンドはスキップされます.

if( 条件 ){
  コマンド 
  コマンド
  コマンド
} 

複数の条件を順に分岐させたい場合はelse if(){}else{}を使います.条件が満たされない場合は次の分岐へと引き渡され,この手順が繰り返されます.どの条件も満たさない場合のコマンドはelse {}で指定します.

if( 条件 1 ){
  コマンド 1
} else if( 条件 2){
  コマンド 2
} else if( 条件 3) {
  コマンド 3
} ..... {
  .....
} else {
  コマンド n
}

たとえば,実数xの偶奇を判定するプログラムは次の通り.

## x が4のとき ##
x <- 4
if(x %% 2 == 0){ # x %% 2 は「xを2で割った余り」を表す
  cat(x, 'は偶数', sep ='')
} else if(x %% 2 == 1){
  cat(x, 'は奇数', sep = '')
} else{
  cat(x, 'は整数ではない', sep = '')
}
## 4は偶数
## x が43のとき ##
x <- 43
if(x %% 2 == 0){
  cat(x, 'は偶数', sep = '')
} else if(x %% 2 == 1){
  cat(x, 'は奇数', sep = '')
} else{
  cat(x, 'は整数ではない', sep = '')
}
## 43は奇数
## x が円周率のとき ##
x <- pi
if(x %% 2 == 0){
  cat(x, 'は偶数', sep = '')
} else if(x %% 2 == 1){
  cat(x, 'は奇数', sep = '')
} else{
  cat(x, 'は整数ではない', sep = '')
}
## 3.141593は整数ではない

Chapter 7 データハンドリング: dplyr入門

7.1 準備

7.1.1 dplyrとは?

dplyrはデータフレームを効率良く処理するためのパッケージです.tidyverseの中に入っています.

## 新規パッケージをインストール ##
install.packages('tidyverse')

## パッケージを呼び出す ##
library(tidyverse)

tidyversedplyrの他にもggplot2などの便利なパッケージがたくさん入ってます.dplyrだけを使用したい場合は以下のコマンドでOKです.

library(dplyr)

7.1.2 dplyrの文法

パイプ%>%を用いて操作途中の結果を次の操作へ渡すこと点が特徴的です.例えば,

df %>% 
  コマンド 1 %>% 
  コマンド 2 %>% 
  コマンド 3 ...

上の例ではデータフレームdfに対してコマンド 1, コマンド 2, …を順に実行していきます.特にdfを操作してdf_newへと変換する場合は次のようなコードになります.

df_new <- df %>% 
  コマンド 1 %>% 
  コマンド 2 %>% 
  コマンド 3 ...

上のコードでは「dfコマンド 1, コマンド 2, …を実行したもの」をdf_newに代入しています.

7.2 使用データ

パッケージggplot2からmpgという自動車に関するデータを取得します.

## データの取得 ##
data(mpg, package = "ggplot2")

## 最初の6行を確認 ##
head(mpg)
## # A tibble: 6 x 11
##   manufacturer model displ  year   cyl trans drv     cty   hwy fl    class
##   <chr>        <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 audi         a4      1.8  1999     4 auto… f        18    29 p     comp…
## 2 audi         a4      1.8  1999     4 manu… f        21    29 p     comp…
## 3 audi         a4      2    2008     4 manu… f        20    31 p     comp…
## 4 audi         a4      2    2008     4 auto… f        21    30 p     comp…
## 5 audi         a4      2.8  1999     6 auto… f        16    26 p     comp…
## 6 audi         a4      2.8  1999     6 manu… f        18    26 p     comp…
## 列名を確認 ##
colnames(mpg)
##  [1] "manufacturer" "model"        "displ"        "year"        
##  [5] "cyl"          "trans"        "drv"          "cty"         
##  [9] "hwy"          "fl"           "class"

7.3 dplyrを使ったデータフレーム処理

データフレームに様々な処理を行ってみましょう.

7.3.1 select(): 列(変数)の選択

select()は列を選択する関数です.最初の引数はデータ,2番目以降の引数は列名です.

mpg_new <- select(mpg, manufacturer, model)

# 確認
head(mpg_new)
## # A tibble: 6 x 2
##   manufacturer model
##   <chr>        <chr>
## 1 audi         a4   
## 2 audi         a4   
## 3 audi         a4   
## 4 audi         a4   
## 5 audi         a4   
## 6 audi         a4

dplyrなどのtidyverseに含まれるパッケージのコマンドの多くは最初の引数でデータを指定します.データの指定はパイプ%>%を使って省略できます.次の例ではselect()の最初の引数mpgがパイプ%>%によって引き継がれています.

mpg_new <- mpg %>% 
  select(manufacturer, model)

# 確認
head(mpg_new)
## # A tibble: 6 x 2
##   manufacturer model
##   <chr>        <chr>
## 1 audi         a4   
## 2 audi         a4   
## 3 audi         a4   
## 4 audi         a4   
## 5 audi         a4   
## 6 audi         a4

列名ではなく列番号でも指定できます.

mpg_new <- mpg %>% 
  select(1, 4, 3)

# 確認
head(mpg_new)
## # A tibble: 6 x 3
##   manufacturer  year displ
##   <chr>        <int> <dbl>
## 1 audi          1999   1.8
## 2 audi          1999   1.8
## 3 audi          2008   2  
## 4 audi          2008   2  
## 5 audi          1999   2.8
## 6 audi          1999   2.8

7.3.2 filter(): 行(観測)の選択

filter()は行を選択します.引数は何らかの条件です.

mpg_new <- mpg %>% 
  filter(year == 1999)

# 確認
head(mpg_new, n = 10)
## # A tibble: 10 x 11
##    manufacturer model     displ  year   cyl trans  drv     cty   hwy fl   
##    <chr>        <chr>     <dbl> <int> <int> <chr>  <chr> <int> <int> <chr>
##  1 audi         a4          1.8  1999     4 auto(… f        18    29 p    
##  2 audi         a4          1.8  1999     4 manua… f        21    29 p    
##  3 audi         a4          2.8  1999     6 auto(… f        16    26 p    
##  4 audi         a4          2.8  1999     6 manua… f        18    26 p    
##  5 audi         a4 quatt…   1.8  1999     4 manua… 4        18    26 p    
##  6 audi         a4 quatt…   1.8  1999     4 auto(… 4        16    25 p    
##  7 audi         a4 quatt…   2.8  1999     6 auto(… 4        15    25 p    
##  8 audi         a4 quatt…   2.8  1999     6 manua… 4        17    25 p    
##  9 audi         a6 quatt…   2.8  1999     6 auto(… 4        15    24 p    
## 10 chevrolet    c1500 su…   5.7  1999     8 auto(… r        13    17 r    
## # … with 1 more variable: class <chr>

次のように複数のコマンドを組み合わせて使用することも可能です(それこそがtidyverseの醍醐味です).

mpg_new <- mpg %>% 
  filter(year == 1999, manufacturer == 'toyota') %>% 
  select(manufacturer, model, displ, year)

# 確認
head(mpg_new, n = 10)
## # A tibble: 10 x 4
##    manufacturer model        displ  year
##    <chr>        <chr>        <dbl> <int>
##  1 toyota       4runner 4wd    2.7  1999
##  2 toyota       4runner 4wd    2.7  1999
##  3 toyota       4runner 4wd    3.4  1999
##  4 toyota       4runner 4wd    3.4  1999
##  5 toyota       camry          2.2  1999
##  6 toyota       camry          2.2  1999
##  7 toyota       camry          3    1999
##  8 toyota       camry          3    1999
##  9 toyota       camry solara   2.2  1999
## 10 toyota       camry solara   2.2  1999

7.3.3 group_by()/ungroup(): グループ化/解除

group_by()はデータセットをグループ化するコマンドです.次の例では変数yearごとにグループ化しています.

mpg_new <- mpg %>% 
  group_by(year)

# 確認
head(mpg_new, n = 10)
## # A tibble: 10 x 11
## # Groups:   year [2]
##    manufacturer model    displ  year   cyl trans   drv     cty   hwy fl   
##    <chr>        <chr>    <dbl> <int> <int> <chr>   <chr> <int> <int> <chr>
##  1 audi         a4         1.8  1999     4 auto(l… f        18    29 p    
##  2 audi         a4         1.8  1999     4 manual… f        21    29 p    
##  3 audi         a4         2    2008     4 manual… f        20    31 p    
##  4 audi         a4         2    2008     4 auto(a… f        21    30 p    
##  5 audi         a4         2.8  1999     6 auto(l… f        16    26 p    
##  6 audi         a4         2.8  1999     6 manual… f        18    26 p    
##  7 audi         a4         3.1  2008     6 auto(a… f        18    27 p    
##  8 audi         a4 quat…   1.8  1999     4 manual… 4        18    26 p    
##  9 audi         a4 quat…   1.8  1999     4 auto(l… 4        16    25 p    
## 10 audi         a4 quat…   2    2008     4 manual… 4        20    28 p    
## # … with 1 more variable: class <chr>

左上の“Groups:”を見るとyearによってちゃんとグループが作られているのが確認できます.でも実はグループ化しただけではデータは何も変わりません.グループ化は以降のセクションで紹介するsummarize()mutate()と組み合わせることで初めて効力を発揮します.
複数の変数でグループ化することもできます.次の例では企業×年度をグループとしています.

mpg_new <- mpg %>% 
  group_by(manufacturer, year)

# 確認
head(mpg_new, n = 10)
## # A tibble: 10 x 11
## # Groups:   manufacturer, year [2]
##    manufacturer model    displ  year   cyl trans   drv     cty   hwy fl   
##    <chr>        <chr>    <dbl> <int> <int> <chr>   <chr> <int> <int> <chr>
##  1 audi         a4         1.8  1999     4 auto(l… f        18    29 p    
##  2 audi         a4         1.8  1999     4 manual… f        21    29 p    
##  3 audi         a4         2    2008     4 manual… f        20    31 p    
##  4 audi         a4         2    2008     4 auto(a… f        21    30 p    
##  5 audi         a4         2.8  1999     6 auto(l… f        16    26 p    
##  6 audi         a4         2.8  1999     6 manual… f        18    26 p    
##  7 audi         a4         3.1  2008     6 auto(a… f        18    27 p    
##  8 audi         a4 quat…   1.8  1999     4 manual… 4        18    26 p    
##  9 audi         a4 quat…   1.8  1999     4 auto(l… 4        16    25 p    
## 10 audi         a4 quat…   2    2008     4 manual… 4        20    28 p    
## # … with 1 more variable: class <chr>

グループを解除したいときはungroup()を指定します.先ほどのグループを解除してみましょう.

mpg_new <- mpg_new %>% 
  ungroup()

# 確認
head(mpg_new)
## # A tibble: 6 x 11
##   manufacturer model displ  year   cyl trans drv     cty   hwy fl    class
##   <chr>        <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 audi         a4      1.8  1999     4 auto… f        18    29 p     comp…
## 2 audi         a4      1.8  1999     4 manu… f        21    29 p     comp…
## 3 audi         a4      2    2008     4 manu… f        20    31 p     comp…
## 4 audi         a4      2    2008     4 auto… f        21    30 p     comp…
## 5 audi         a4      2.8  1999     6 auto… f        16    26 p     comp…
## 6 audi         a4      2.8  1999     6 manu… f        18    26 p     comp…

左上に“Groups:”という欄がないのでグループが解除されたことが確認できます.

7.3.4 summarize(): 集計

先ほど説明したgroup()で指定したグループごとに変数を何らかの形で集計してみます.集計を指示するコマンドはsummarize()です.引数は新しい変数名 = 集計の内容のようなイメージ.

mpg_new <- mpg %>% 
  group_by(manufacturer, year) %>% 
  summarize(displ_mean = mean(displ)) %>% 
  ungroup()
## `summarise()` has grouped output by 'manufacturer'. You can override using the `.groups` argument.
# 確認
head(mpg_new, n = 10)
## # A tibble: 10 x 3
##    manufacturer  year displ_mean
##    <chr>        <int>      <dbl>
##  1 audi          1999       2.36
##  2 audi          2008       2.73
##  3 chevrolet     1999       4.97
##  4 chevrolet     2008       5.12
##  5 dodge         1999       4.32
##  6 dodge         2008       4.42
##  7 ford          1999       4.45
##  8 ford          2008       4.66
##  9 honda         1999       1.6 
## 10 honda         2008       1.85

上の例では各グループごとに変数displを平均して集計しましたが,単純に観測数を数えたい場合はn()を使用します.

mpg_new <- mpg %>% 
  group_by(manufacturer, year) %>% 
  summarize(count = n()) %>% 
  ungroup()
## `summarise()` has grouped output by 'manufacturer'. You can override using the `.groups` argument.
# 確認
head(mpg_new, n = 10)
## # A tibble: 10 x 3
##    manufacturer  year count
##    <chr>        <int> <int>
##  1 audi          1999     9
##  2 audi          2008     9
##  3 chevrolet     1999     7
##  4 chevrolet     2008    12
##  5 dodge         1999    16
##  6 dodge         2008    21
##  7 ford          1999    15
##  8 ford          2008    10
##  9 honda         1999     5
## 10 honda         2008     4

7.3.5 mutate(): 新しい変数作成

mutate()は新しい変数を作成するコマンドです.次の例はctyの自然対数をln_ctyという新しい変数として作成しています.

mpg_new <- mpg %>% 
  mutate(ln_cty = log(cty))

# 確認
mpg_new %>% 
  select(cty, ln_cty) %>% 
  head()
## # A tibble: 6 x 2
##     cty ln_cty
##   <int>  <dbl>
## 1    18   2.89
## 2    21   3.04
## 3    20   3.00
## 4    21   3.04
## 5    16   2.77
## 6    18   2.89

mutate()は先ほど説明したgroup()と組み合わせて使用すると便利なときがあります.

mpg_new <- mpg %>% 
  group_by(manufacturer, year) %>% 
  mutate(displ_mean = mean(displ)) %>% 
  ungroup()

# 確認
mpg_new %>% 
  select(manufacturer, model, year, displ_mean)
## # A tibble: 234 x 4
##    manufacturer model       year displ_mean
##    <chr>        <chr>      <int>      <dbl>
##  1 audi         a4          1999       2.36
##  2 audi         a4          1999       2.36
##  3 audi         a4          2008       2.73
##  4 audi         a4          2008       2.73
##  5 audi         a4          1999       2.36
##  6 audi         a4          1999       2.36
##  7 audi         a4          2008       2.73
##  8 audi         a4 quattro  1999       2.36
##  9 audi         a4 quattro  1999       2.36
## 10 audi         a4 quattro  2008       2.73
## # … with 224 more rows

グループ化したデータにおけるmutate()summarize()の違いは行数を確認すれば一目瞭然です.

# summarize() ver
mpg_summarize <- mpg %>% 
  group_by(manufacturer, year) %>% 
  summarize(displ_mean = mean(displ)) %>% 
  ungroup()
## `summarise()` has grouped output by 'manufacturer'. You can override using the `.groups` argument.
# mutate() ver
mpg_mutate <- mpg %>% 
  group_by(manufacturer, year) %>% 
  mutate(displ_mean = mean(displ)) %>% 
  ungroup()

# 行数(観測数) を確認
nrow(mpg) ; nrow(mpg_summarize) ; nrow(mpg_mutate)
## [1] 234
## [1] 30
## [1] 234

7.3.6 pivot_*():wide型からlong型への変換 次回

7.3.7 arrange():行の並び替え

次回

7.3.8 distinct(): 重複行の操作

次回

7.3.9 *_join(): データフレームの結合 次回