tidy data (整然データ)
データフレームはリストの一種で,同じ長さのベクトルを束ねたオブジェクトである。1つの列は1つの変数であり,1つの行は1つの観測単位 (横断面データであれば観測固体,時系列データであれば観測時点)である。たとえば,5人の個人の氏名,性別,身長,体重が記録されたデータであれば,データフレームは10行4列となる。4つの列 (氏名,性別,身長,体重)はそれぞれ長さが10のベクトルであり,5つの行はそれぞれがひとりひとりの個人に対応する。
また,irisデータは,150行5列のデータフレームであるが,各列 (Sepal.Length, Sepal.Width, Petal.Length, Petal.Width, Species)はそれぞれ長さが150のベクトルである。そして,各行はひとつひとつの観測個体のデータを表している。
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.4 ✔ readr 2.1.5
✔ forcats 1.0.0 ✔ stringr 1.5.1
✔ ggplot2 3.5.2 ✔ tibble 3.2.1
✔ lubridate 1.9.4 ✔ tidyr 1.3.1
✔ purrr 1.0.4
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 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.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
このようなデータは,tidy data (整然データ)と呼ばれる。tidy dataとは,以下の4つの条件を満たすデータのことである。
- 1つの列が1つの変数,1つの変数が1つの列
- 1つの行が1つの観測単位,1つの観測単位が1つの行
- 1つの値が1つのセル,1つのセルに1つの値
- 観測単位が1つに統一されている
tidy dataの概念は,Hadley Wichhamによって提唱された。Wickham (2014)では,tidy dataの条件として上記の1,2,4があげられている。一方,tidyverseに含まれているtidyrパッケージの説明では,1,2,3があげられている。ここでは,4つの条件すべてを満たすデータをtidy dataと呼ぶことにする。
tidy dataは構造と意味が一致していて分析の際に扱いやすい形である (必ずしも見た目にわかりやすいというわけではない)。
tidy dataではないデータの典型例を1つ示そう。
たこ焼き |
4000円 |
5000円 |
お茶 |
1000円 |
1500円 |
チョコレート |
2000円 |
2500円 |
このデータは,売上げという1つの変数が2列にまたがっており,1つの列に日付と売上げという2つの変数が記録されている。1つの列が1つの変数となっていないため,このデータはtidy dataではない。
このデータをtidy dataにするには,日付と売上げをそれぞれ1つの列にまとめ,1つの列が1つの変数になるようにする。
たこ焼き |
2月3日 |
4000円 |
たこ焼き |
2月4日 |
5000円 |
お茶 |
2月3日 |
1000円 |
お茶 |
2月4日 |
1500円 |
チョコレート |
2月3日 |
2000円 |
チョコレート |
2月4日 |
2500円 |
当然,このデータに小計や合計の行を加えると,商品ごとの売上げと小計や合計という観測単位が統一されていない行が混在することになるので,tidy dataではなくなる。
tidyverse
tidyverseは,モダンなデータ分析を行うためのパッケージをひとまとめにしたパッケージである。tidyverseに含まれるパッケージは,設計の哲学,文法,データ構造を共有している。
tidyverseに含まれるパッケージは,以下の9つである。tidyverseを読み込めば,すべてのパッケージが自動的に読み込まれる。
それぞれのパッケージのページには,関数の使い方を簡潔にまとめたチートシートが用意されている。印刷しておくと良いだろう。
tidyverseによるデータフレームの操作
readr
パッケージによるデータの読込み
分析したいデータをRのデータフレームに読み込むためには,readr
パッケージを利用する。readr
パッケージには,csvファイルを読み込むread_csv()
,固定長ファイルを読み込むread_fwf()
などの関数が含まれ,さまざまな形式のデータを読み込むことができる。
通常はcsvファイルを読み込むことができれば十分だろう (Excelのデータはcsvに保存することができる)。base Rのread.csv()
関数でも十分だが,readr
パッケージのread_csv()
関数の方が,読込み速度が速い。
dplyr
パッケージによるデータフレームの操作
dplyr
パッケージは,データフレームを操作するためのパッケージである。すでにいくつかの関数については,データの要約 (記述統計量)や回帰分析で利用した。ここでは,よく使うものをリストアップしておく。
新しい変数の追加 (mutate)
dplyr::mutate()
関数を用いると,新しい変数を追加することができる。具体的な使い方は回帰分析を参照。
列 (変数)の抽出 (select)
dplyr::select()
関数を用いると,データフレームから列 (変数)を抽出することができる。具体的な使い方はデータの要約 (記述統計量)を参照。
select()
関数で取り出されたデータフレームは,変数の並び順がselect()
関数の引数に指定した順になる。したがって,変数を並び替えたい場合にもselect()
関数を用いることができる。なお,変数の列を移動させるには,dplyr::relocate()
関数も用意されている。
行 (観測単位)の抽出 (filter)
dplyr::filter()
関数を用いると,データフレームから行 (観測単位)を抽出することができる。具体的な使い方はデータの要約 (記述統計量)を参照。
要約統計表の作成 (summarize, group_by)
dplyr::summarize()
関数を用いると,データフレームの要約統計量を計算することができる。具体的な使い方はデータの要約 (記述統計量)を参照。また,dplyr::group_by()
関数を用いると,データフレームをグループに分けることができる。具体的な使い方はデータの要約 (記述統計量)を参照。
データの並替え (arrange)
dplyr::arrange()
関数を用いると,データフレームの行を並べ替えることができる。第1引数にはデータフレーム,第二引数以降には並替えに用いる変数を優先する順に指定する。逆順に並替えたい場合は,その変数をdesc()
関数でラップする。
tidyr
パッケージによるデータのtidy data化
tidyr
パッケージは,データフレームをtidy dataに整理するためのパッケージである。とくに,pivot_longer()
関数とpivot_wider()
関数は,wide型データとlong型データを相互に変換するための関数で,使う機会が多い。
long型データとwide型データ
1つの行が観測単位を表し,1つ1つの列に変数が記録されたデータをwide型データという。それに対して,1つの行が観測値を表し,変数名と値がそれぞれの列に記録されたデータをlong型データという。言語で理解するよりは,具体例を見た方が理解しやすいだろう。
次のデータは,1つの行が観測単位を表し,1つ1つの列に変数が記録されているため,wide型データである。
wide <-tribble(
~氏名, ~`労働所得 (万円)`, ~`不労所得 (万円)`,
"大阪太郎", 300, 100,
"山田花子", 800, 200,
"神戸次郎", 500, 150
)
wide
# A tibble: 3 × 3
氏名 `労働所得 (万円)` `不労所得 (万円)`
<chr> <dbl> <dbl>
1 大阪太郎 300 100
2 山田花子 800 200
3 神戸次郎 500 150
このデータをlong型データに変換すると,次のようになる。
long <- wide |>
pivot_longer(
cols = c(`労働所得 (万円)`, `不労所得 (万円)`),
names_to = "income_source",
values_to = "income")
long
# A tibble: 6 × 3
氏名 income_source income
<chr> <chr> <dbl>
1 大阪太郎 労働所得 (万円) 300
2 大阪太郎 不労所得 (万円) 100
3 山田花子 労働所得 (万円) 800
4 山田花子 不労所得 (万円) 200
5 神戸次郎 労働所得 (万円) 500
6 神戸次郎 不労所得 (万円) 150
通常,人間が見た目で理解しやすいのはwide型であるが,Rで分析を行う際には,long型データの方が扱いやすいことも多い (ggplot2では,long型データが前提になっている)。また,tidy dataになっていないwide型データは,long型に変換することでtidy dataにすることができる場合がある。
long型データ=tidy dataというわけではないし,すべてのデータをlong型に変換するような必要はないことに注意。分析内容によってはlong型データよりもwide型データの方が扱いやすい場合もある。たとえば,要約統計表を作成したり回帰分析を行ったりする場合は,wide型データの方が扱いやすい。実際には,データをwide型とlong型との間で相互に変換しながら分析を行う。
pivot_longer()関数
tidyr::pivot_longer()
関数を用いると,すでに上の例で示したとおり,wide型データをlong型データに変換することができる。第1引数はデータフレーム,第2引数以降は以下の通り。
cols
引数には,変数名の列と値の列との2列に変換する変数名を指定する。
names_to
引数には,変換後のデータフレームで,変数名を格納するための列の名前を指定する。
values_to
引数には,変換後のデータフレームで,値を格納するための列の名前を指定する。
この場合は,cols
引数には,労働所得と不労所得の列を指定している。これにより,氏名の列はそのままで,労働所得と不労所得の列が,変数名と値の2列に変換される。names_to
,values_to
は省略可能で,省略した場合,変数名を格納する列はname
,値を格納する列はvalue
という名前になる。
pivot_wider()関数
tidyr::pivot_wider()
関数を用いると,long型データをwide型データに変換することができる。
wide <- long |>
pivot_wider(
names_from = income_source,
values_from = income
)
wide
# A tibble: 3 × 3
氏名 `労働所得 (万円)` `不労所得 (万円)`
<chr> <dbl> <dbl>
1 大阪太郎 300 100
2 山田花子 800 200
3 神戸次郎 500 150
第1引数はデータフレーム,第2引数以降は以下の通り。
names_from
引数には,変数名が格納されている列を指定する。
values_from
引数には,値が格納されている列の名前を指定する。