Chapter 4 データ・ハンドリング
データに新しく変数を加えたり、データの形式を変えるなど、より高度で複雑なデータの操作について学んでいく。
この章では、tidyverse
というパッケージに入っている関数を解説する。
- 変数の作成
- データの抽出
- パイプ
- グルーピング
- データの変換
- データの結合
- データの読み込み
4.1 パッケージのロード
まず、この章で使うパッケージのロードをする(初めて使う場合は、マシンに予めパッケージをインストールする必要がある)。パッケージのインストール及びロードについては、第2章で解説している。
注意:
以降のプログラムでは、関数を「XXXX::YYYY
」と表現しているが、これらは「XXXX
パッケージに入っているYYYY
という名前の関数を使う」ということを意味している。XXXX::
の部分は基本的に省略しても問題ないが、例えばtidyverse
パッケージ以外もロードしていて、同じ名前の関数が別のパッケージに含まれている場合には、思った通りの結果が表示されない場合もある。外部パッケージの関数を使う場合は、できる限りXXXX::
を付けた方が無難である。
以降では、Rに標準で入っているiris
データを例として、ファイル操作の練習を行う。以下のプログラムを実行し、iris
データをdat
という名前に置き換えて使っていこう。
4.2 変数の作成
dplyr
パッケージに入っているmutate()
を使うと、新たに変数を追加することができる。
mutate()
に、データの名前、新しい変数の順番で入力すると、データの右端に新しい変数を追加してくれる。
dat2 = dplyr::mutate(dat,
new_var = Sepal.Length + Petal.Length,
hoge = ifelse(Species == "setosa", 1, 0))
head(dat2)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species new_var hoge
## 1 5.1 3.5 1.4 0.2 setosa 6.5 1
## 2 4.9 3.0 1.4 0.2 setosa 6.3 1
## 3 4.7 3.2 1.3 0.2 setosa 6.0 1
## 4 4.6 3.1 1.5 0.2 setosa 6.1 1
## 5 5.0 3.6 1.4 0.2 setosa 6.4 1
## 6 5.4 3.9 1.7 0.4 setosa 7.1 1
上の例では、Sepal.Length
とPetal.Length
を足したnew_var
という名前の新しい変数を作っている。更に、「Sepecies
が”setosa
“ならば1, そうでなければ0とする」という条件で新たにhoge
という変数を作っている。
4.3 データの抽出
dplyr
パッケージに入っているselect
や filter
関数を使うと、データの中から必要な部分のみを取り出すことができる。
4.3.1 必要な列のみを取り出す(select)
select()
で、データの名前、取り出したい変数名(複数選択可)の順番で入力すると、指定した変数の列のみを取り出してくれる。
以下には、iris
データからSepal.Length
とPetal.Length
のみを取り出す場合のプログラム例を示す。
## Sepal.Length Petal.Length
## 1 5.1 1.4
## 2 4.9 1.4
## 3 4.7 1.3
## 4 4.6 1.5
## 5 5.0 1.4
## 6 5.4 1.7
上の例では、データの中からSepal.Length
とPetal.Length
の列を取り出している。
4.3.2 条件に合う行を取り出す(filter)
ある条件に合う行のみを取り出したい場合(例えばデータの中から男性のみを取り出したいなど)、filter()
で、データの名前、条件式の順番で入力すると、データの中から条件に合う行のみを取り出してくれる。
以下には、iris
データから、あやめの種類("Species"
)のうち"versicolor"
のみを取り出す場合のプログラム例を示す。
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1 7.0 3.2 4.7 1.4 versicolor
## 2 6.4 3.2 4.5 1.5 versicolor
## 3 6.9 3.1 4.9 1.5 versicolor
## 4 5.5 2.3 4.0 1.3 versicolor
## 5 6.5 2.8 4.6 1.5 versicolor
## 6 5.7 2.8 4.5 1.3 versicolor
データから条件に合う行だけが取り出される。上の例では、「Species
がversicolor
である」行をdat
から取り出している。
「イコール」は=
ではなく、==
と表記していることに注意。つまり、計算式と論理式ではイコールの表現の仕方が異なる。他の論理式の表現については、第2章で説明しているので確認しておこう。例えば、「Sepal.Length
が7以上」という条件で取り出したいときは、dplyr::filter(iris, Sepal.Length >= 7)
とする。
4.4 パイプ
複数のプログラムをつなげることをパイプ処理という。purrr
パッケージで(tidyverse
パッケージをロードすれば自動で使える)、Rでパイプ処理をすることができる。
例えば、iris
データで「あやめの種類のうち"setosa"
のみの行を取り出して、更にSpecies
、Sepal.Length
, Petal.Length
のみの列を取り出したい」という複数の処理をする場合を例として考える。
先程まで学んだ内容で、以下のように複数のプラグラムを段階的に書けばできなくはないが、プログラムが非常に長くなる(プログラムを分けて書くと途中でミスも生じやすくなる)。
dat = iris #irisデータをdatという名前に置き換える
dat2 = dplyr::filter(dat, Species == "setosa") #まずSpeciesのうち、setosaのみを取り出す。dat2という名前で保存する。
dat3 = dplyr::select(dat2, Species, Sepal.Length, Petal.Length) #別の名前で保存し直したdat2から、Sepal.LengthとPetal.Lengthの列を取り出す。dat3という名前で保存する
head(dat3)
## Species Sepal.Length Petal.Length
## 1 setosa 5.1 1.4
## 2 setosa 4.9 1.4
## 3 setosa 4.7 1.3
## 4 setosa 4.6 1.5
## 5 setosa 5.0 1.4
## 6 setosa 5.4 1.7
パイプ(%>%
)を使えば、このプログラムを1文で書くことができる。
dat = iris #irisデータをdatという名前に置き換える
dat2 = dat %>% dplyr::filter(., Species == "setosa") %>%
dplyr::select(., Species, Sepal.Length, Petal.Length)
head(dat2)
## Species Sepal.Length Petal.Length
## 1 setosa 5.1 1.4
## 2 setosa 4.9 1.4
## 3 setosa 4.7 1.3
## 4 setosa 4.6 1.5
## 5 setosa 5.0 1.4
## 6 setosa 5.4 1.7
%>%
はプログラムを渡していく関数であり、.
はそのプログラム以前の結果を示している。iris
データをfilter
に渡し、その結果をselect
に渡している。
なお、.
は省略しても良い(以降でも、.
は省略して表記する)。
4.5 グルーピング
パイプを利用することで、グループごとに統計量(平均値や標準偏差など)を算出することができる。
iris
データを例として、グループごとに平均や標準偏差を計算する方法を覚えよう。
あやめの種類ごとに、がくの長さの平均値と標準偏差を算出してみる。
先ほど学んだパイプ処理(%>%
)に加え、dplyr
パッケージのgroup_by
とsummarise
関数を利用する。
dat = iris #irisデータをdatという名前に置き換える
dat2 = dat %>%
dplyr::group_by(Species) %>%
dplyr::summarise(Mean = mean(Sepal.Width, na.rm = TRUE),
SD = sd(Sepal.Width, na.rm = TRUE),
N = length(Sepal.Width))
dat2
## # A tibble: 3 × 4
## Species Mean SD N
## <fct> <dbl> <dbl> <int>
## 1 setosa 3.43 0.379 50
## 2 versicolor 2.77 0.314 50
## 3 virginica 2.97 0.322 50
group_by()
はグループ変数を作成する関数である。データの中でグループとして使いたい変数を括弧内に指定する。
summarise()
は、複数の関数を実行させる関数である。この例では、mean()
、sd()
, length()
の3つの関数を実行し、それぞれの結果をMean, SD, Nという別の名前で保存している。
4.6 データの変換
tidyr
パッケージに入っているpivot_longer()
とpivot_wider()
を使うと、データの並び替えなどをすることができる。
4.6.1 wide型とlong型の区別
まず、データのレイアウトには、wide型とlong型の二種類があることを理解しよう。
以下のデータを例として説明する。A, B, Cの3人の参加者が、X, Y, Z条件の3つの条件で実験課題を行ったとする。
まずは、以下のプログラムを実行してサンプルデータを作成しよう。
dat_wide = data.frame(Subject = c("A","B","C"),
X = c(6,2,7),
Y = c(9,3,4),
Z = c(7,5,7),
Gender = c("M", "F", "F"),
Age = c(18, 19, 20)) #サンプルデータを作る
dat_wide
## Subject X Y Z Gender Age
## 1 A 6 9 7 M 18
## 2 B 2 3 5 F 19
## 3 C 7 4 7 F 20
このようにデータの入力方法として、1行につき1人の参加者の情報を入力するやり方がある(実験や調査でデータを入力する際も、このレイアウトの方が入力しやすいだろう)。このようなデータのレイアウトをwide型という。
同じデータを、以下のようなレイアウトで表現することもできる。同じく、以下のプログラムを実行して、サンプルデータを作ろう。
dat_long = data.frame(Subject = sort(rep(c("A","B","C"), 3)),
Condition = rep(c("X","Y","Z"), 3),
Score = c(6,9,7,2,3,5,7,4,7),
Gender = c("M", "M", "M", "F","F","F","F","F", "F"),
Age = sort(rep(c(18,19,20), 3)))
dat_long
## Subject Condition Score Gender Age
## 1 A X 6 M 18
## 2 A Y 9 M 18
## 3 A Z 7 M 18
## 4 B X 2 F 19
## 5 B Y 3 F 19
## 6 B Z 5 F 19
## 7 C X 7 F 20
## 8 C Y 4 F 20
## 9 C Z 7 F 20
実験成績ごとに1行ずつでデータが作られている。すなわち、同じ参加者1人につき3行のデータがある。このようなデータの方をlong型と呼ぶ。
4.6.2 wide型からlong型に変換
tidyr
パッケージのpivot_longer()
を使う。
dat_long2 = dat_wide %>%
tidyr::pivot_longer(cols = c("X", "Y", "Z"),
names_to = "Condition", values_to = "Score")
dat_long2
## # A tibble: 9 × 5
## Subject Gender Age Condition Score
## <chr> <chr> <dbl> <chr> <dbl>
## 1 A M 18 X 6
## 2 A M 18 Y 9
## 3 A M 18 Z 7
## 4 B F 19 X 2
## 5 B F 19 Y 3
## 6 B F 19 Z 5
## 7 C F 20 X 7
## 8 C F 20 Y 4
## 9 C F 20 Z 7
cols =
で、並べ替える変数を指定する。names_to =
で新しく作られるグループを意味する列の名前、values_to =
で値を意味する列の名前を指定する。
4.7 データの結合
複数のデータを結合したい場合は、dplyr
パッケージのjoin
関数を使うとよい。join
関数には、left_join
, full_join
など、いくつかの種類が用意されている。
サンプルデータを使いながら、手順について説明する。まず、以下のプログラムを実行して、サンプルデータを作ろう。
dat_sample = data.frame(Subject = c("A","B","C"),
X = c(6,2,7),
Y = c(9,3,4),
Z = c(7,5,7),
Gender = c("M", "F", "F"),
Age = c(18, 19, 20))
dat_sample
## Subject X Y Z Gender Age
## 1 A 6 9 7 M 18
## 2 B 2 3 5 F 19
## 3 C 7 4 7 F 20
実験で3人の参加者A, B, Cについて、X, Y, Zのデータを取ったとする。
更に、2人の参加者(AとB)に追加で実験を行い、Wのデータを取ったとする。
## Subject W
## 1 A 8
## 2 B 3
dat_sample
とdat_sample2
のデータを結合して、一つのデータにしたい。
full_join()
で結合したい2つのデータ、更に結合する際にキーとなる変数(2つのデータに共通して存在する変数)をby=
で指定すると2つのデータを結合してくれる。
なお、by=
を省くと、自動で2つのデータに共通する変数を見つけて、それを手がかりに結合してくれる。
## Subject X Y Z Gender Age W
## 1 A 6 9 7 M 18 8
## 2 B 2 3 5 F 19 3
## 3 C 7 4 7 F 20 NA
full_join()
だと、2つのデータをすべてつなげてくれる。データが含まれていない部分は、欠損になる(data_sample2
に参加者Cのデータはないので、欠損になっている)。
left_join()
だと、left_join()
で左側に入力したデータを含む部分のみをつなげてくれる。
## Subject W X Y Z Gender Age
## 1 A 8 6 9 7 M 18
## 2 B 3 2 3 5 F 19
4.8 データの読み込み
Rにもともと入っているread.csv()
を使えばcsvファイルを読み込むことができるが、readr
パッケージの関数を使うと大量のデータが含まれるファイルも高速で読み込んでくれる。また、readxl
パッケージの関数を使えば、Excelファイルも読み込んでくれる。
4.8.1 readr
様々な形式のファイルを高速で読み書きことを目標としたパッケージ。
## X Y Gender
## 1 4 6 M
## 2 7 3 F
## 3 7 6 M
## 4 3 3 M
## 5 4 4 F
## # A tibble: 5 × 3
## X Y Gender
## <dbl> <dbl> <chr>
## 1 4 6 M
## 2 7 3 F
## 3 7 6 M
## 4 3 3 M
## 5 4 4 F
read.csv()
ではなく、read_csv()
なので注意(ドットではなく、アンダースコア)。
ファイルを書き出すための関数も用意されている。
ここではwrite_excel_csv()
を使っているが、単にwrite_csv()
でも可。
また、read_csv()
で読み込んだファイルは、データフレームではなく、tibbleという形式になる。
tibble
tibbleとは、Rのデータ形式の一つである。
データフレームの可読性を向上させたものが、tibbleである。コンソールにはデータ全てではなく、最初の10行程度のみ、列も画面に入る範囲のみが表示される。
as_tibble()
でデータフレームをtibble形式にすることもできる。
## # A tibble: 150 × 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <dbl> <dbl> <dbl> <dbl> <fct>
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
## 4 4.6 3.1 1.5 0.2 setosa
## 5 5 3.6 1.4 0.2 setosa
## 6 5.4 3.9 1.7 0.4 setosa
## 7 4.6 3.4 1.4 0.3 setosa
## 8 5 3.4 1.5 0.2 setosa
## 9 4.4 2.9 1.4 0.2 setosa
## 10 4.9 3.1 1.5 0.1 setosa
## # ℹ 140 more rows
tibbleだとデータをすべて閲覧することはできないが、すべて閲覧したい場合はView()
を使えばよい。
確認問題
問1
iris
データから、1)Species
がversicolor
である行を選び、2) Species
, Petal.Length
及びPetal.Width
の列を取り出し、3) Petal.Length
とPetal.Width
を足し合わせた変数hoge
を作るという一連の処理を、パイプ処理を使ってプログラム1行でやってみよう。