脱・R初心者講義パート1 tidyverseパッケージ群を何となく理解する
はじめに
今回は脱・R初心者講義と題しまして、「神」ことハドリーウィッカム氏の開発したtidyverseという一連のパッケージ群のコンセプトや使用方法について解説していきます。
プロジェクトの活用
解説に行く前に、プロジェクト機能について軽く触れておきます。
RStudioにはプロジェクトという機能があり、プロジェクトごとに環境(作業ディレクトリの場所、実行の履歴やオブジェクト(変数や関数)など)を保存でき、プロジェクトを開くとすぐに、プロジェクトごとの環境が利用できて便利です。
プロジェクトの導入は必須ではありませんが、Rを中心にプロジェクトを進めていく際には活用をお勧めします。
プロジェクトについて詳しくは以下を参考にしてください。
http://wakupro.sakura.ne.jp/archives/491
Tidyverseパッケージ群の導入
tidyverseはRでデータ分析をするための一連の流れを網羅する非常に便利なパッケージ群です。
Rの標準関数でもデータ分析を行うことはできますが、tidyverse群の関数を用いたほうが圧倒的に便利かつ速いので、Rでの操作はtidyverse的に行うようにしています。
RStudioでパッケージをインストールするときは、install.package("パッケージ名")
もしくはメニューバーの「Tools」→「Install
Package」からパッケージ名を検索してインストールします。
また、実際にパッケージを使う際にはlibrary(パッケージ名)
でパッケージを呼び出す必要があります。ライブラリ設定はRを起動するたびに必要になります。
install.packages("tidyverse") library(tidyverse)
tidyverseに含まれる主なパッケージは、
dplyr(データフレーム操作、変換)
ggplot(可視化)
tidyr(整然データへの変換)
などがあります。
整然データ
tidyverseパッケージ群は、扱うデータの形式として「整然データ(tidy data)」を前提としています。
Rを用いなくとも、整然データの形式に変換することはデータ分析をとてもやりやすくしてくれます。
簡潔にまとめると、1行に1レコードのみが入った、通常縦に長く伸びる行列形式の表のことです。
整然データについて詳しくは以下のページが詳しいです。
整然データとは何か
dplyr
dplyrは効率的にデータフレームを操作するためのパッケージで、(dplyrに限らずtidyverse群すべて)パイプライン演算子%>%
を使った記述が非常に簡単なのが特徴です。
パイプライン演算子を使った処理x %>% f(a)
はf(x, a)
と等価で、
%>%
は左のx
を右側の関数f()
の第一因数として渡す役割を果たしています。
パイプ演算子はCtrl+Shift+M
で挿入できます。
パイプライン記述は見やすくかつコードの発想が容易になり、見通しの良い記述の手助けをしてくれます。
次からはdplyrの代表的な関数を紹介していきます。
また、取り扱うデータとしてRに標準で組み込まれているデータセットiris
を用います。
head(iris) %>% kable(align = "c",format = "html")
Sepal.Length | Sepal.Width | Petal.Length | Petal.Width | Species |
---|---|---|---|---|
5.1 | 3.5 | 1.4 | 0.2 | setosa |
4.9 | 3.0 | 1.4 | 0.2 | setosa |
4.7 | 3.2 | 1.3 | 0.2 | setosa |
4.6 | 3.1 | 1.5 | 0.2 | setosa |
5.0 | 3.6 | 1.4 | 0.2 | setosa |
5.4 | 3.9 | 1.7 | 0.4 | setosa |
filter
条件に合致した行を抽出するコード。
iris %>% filter(Species=="virginica",Sepal.Length>6.0) %>% ##virginica種でがく辺の長さが6cm以上の行を抽出 head() %>% kable(align = "c",format = "html")
Sepal.Length | Sepal.Width | Petal.Length | Petal.Width | Species |
---|---|---|---|---|
6.3 | 3.3 | 6.0 | 2.5 | virginica |
7.1 | 3.0 | 5.9 | 2.1 | virginica |
6.3 | 2.9 | 5.6 | 1.8 | virginica |
6.5 | 3.0 | 5.8 | 2.2 | virginica |
7.6 | 3.0 | 6.6 | 2.1 | virginica |
7.3 | 2.9 | 6.3 | 1.8 | virginica |
select
条件に合致した列を抽出するコード。列位置や列名など様々な列指定の方法が用意されている。
iris %>% select(-Sepal.Width) %>% ##列名指定(-をつけて削除) select(c(1,4)) %>% ##列位置指定 head() %>% kable(align = "c",format = "html")
Sepal.Length | Species |
---|---|
5.1 | setosa |
4.9 | setosa |
4.7 | setosa |
4.6 | setosa |
5.0 | setosa |
5.4 | setosa |
group_by
ある変数の値でデータフレームをグループ化する。
グループごとに処理をすることが可能になる。
後述するsummarise
などと一緒に使うことが多い。
mutate
データフレームに新しい列を追加したり、既存の列を操作したりする関数。
## SpeciesごとのSepal.Length平均値を新たな列として追加 iris %>% group_by(Species) %>% mutate(mean.Sepal.Length=mean(Sepal.Length)) %>% head() %>% kable(align = "c",format = "html")
Sepal.Length | Sepal.Width | Petal.Length | Petal.Width | Species | mean.Sepal.Length |
---|---|---|---|---|---|
5.1 | 3.5 | 1.4 | 0.2 | setosa | 5.006 |
4.9 | 3.0 | 1.4 | 0.2 | setosa | 5.006 |
4.7 | 3.2 | 1.3 | 0.2 | setosa | 5.006 |
4.6 | 3.1 | 1.5 | 0.2 | setosa | 5.006 |
5.0 | 3.6 | 1.4 | 0.2 | setosa | 5.006 |
5.4 | 3.9 | 1.7 | 0.4 | setosa | 5.006 |
distinct
指定した列の値ごとに1行のみを返す。重複行を削除する時などに使う。
iris %>% group_by(Species) %>% mutate(mean_Sepal.Length=mean(Sepal.Length)) %>% select(mean_Sepal.Length,Species) %>% distinct(Species,.keep_all = TRUE) %>% ##.keep_all=FALSEならキー列のみを返す。 head() %>% kable(align = "c",format = "html")
mean\_Sepal.Length | Species |
---|---|
5.006 | setosa |
5.936 | versicolor |
6.588 | virginica |
summarise
指定した列に関数を適用して1行のデータフレームにまとめる。グループ化されていたらグループごとに適用する。
iris %>% group_by(Species) %>% summarise(total_Sepal.Length=sum(Sepal.Length),min_Petal.Width=min(Petal.Width)) %>% kable(align = "c",format = "html")
Species | total\_Sepal.Length | min\_Petal.Width |
---|---|---|
setosa | 250.3 | 0.1 |
versicolor | 296.8 | 1.0 |
virginica | 329.4 | 1.4 |
ggplot
デフォルトのグラフィック関数と比較したときのggplotのメリットは、
- 図の描きわけが容易
- 図が綺麗
- 図の重ね合わせが容易
などがあります。
一方で単純な図であればデフォルト関数の方がコードが短いぶん楽です。
ggplotのプロット手順は以下のようになっています。
①が楽に出来るようなtidyデータになっていれば、後は簡単です。
散布図、回帰直線
aes()
によってx軸・y軸に取ってくる列や塗りわけのキーとして利用する列を指定します。
ggplot(iris,aes(x=Sepal.Length,y=Petal.Length,col=Species))+ ##キャンバスの設定 geom_point()+ ##以降は図の重ね合わせ geom_smooth(method = "lm") ##回帰モデル「線形」を指定
ちなみに、軸や塗りわけキー指定のaes()
はgeom_()
関数内でも使えます。
なので、関数ごとに別のaes()
を用いて、以下のようなこともできます。
ggplot(iris,aes(x=Sepal.Length,y=Petal.Length))+ geom_point(aes(alpha=Sepal.Width))+ ##点の濃淡をSepal.Widthによって変える geom_smooth(aes(col=Species),method = "lm")
ヒストグラム
ggplot(iris,aes(x=Petal.Length,fill=Species,))+ geom_histogram(position="dodge")
箱ひげ図、バイオリンプロット
ggplot(iris,aes(x=Species,y=Petal.Width))+ geom_boxplot(fill="grey70")+ ##重ねた時にも見やすい色を指定しておく geom_violin(col="orange",fill="orange",alpha=0.5)
tidyr
tidyrは整然データに整形するためのパッケージです。
代表的な関数としては、横長形式を縦長にするpivot_longer()
とそれに対をなすpivot_wider()
、
2つの列を1つにまとめるunite()
とそれに対をなすseparate()
などがあります。
例えば以下のような雑然データを整然にできます。
kaoku=data.frame(客番号=c(1:5), メイン種類=c("テリヤキバーガー","月見バーガー","ハンバーガー","ハンバーガー","テリヤキバーガー"), メイン値段=c(500,600,300,300,500), サイド種類=c("ポテト","ポテト","オニオンフライ",NA,"サラダ"), サイド値段=c(100,100,200,NA,300), ドリンク種類=c("コーラ","オレンジ","オレンジ",NA,"ウーロン茶"), ドリンク価格=c(100,120,120,NA,150)) kaoku %>% kable(align = "c",format = "html")
客番号 | メイン種類 | メイン値段 | サイド種類 | サイド値段 | ドリンク種類 | ドリンク価格 |
---|---|---|---|---|---|---|
1 | テリヤキバーガー | 500 | ポテト | 100 | コーラ | 100 |
2 | 月見バーガー | 600 | ポテト | 100 | オレンジ | 120 |
3 | ハンバーガー | 300 | オニオンフライ | 200 | オレンジ | 120 |
4 | ハンバーガー | 300 | NA | NA | NA | NA |
5 | テリヤキバーガー | 500 | サラダ | 300 | ウーロン茶 | 150 |
unite()
で対応関係にある「種類」と「点数」をまとめておく
kaoku %>% unite(col="メイン",starts_with("メイン")) %>% unite(col="サイド",starts_with("サイド")) %>% unite(col="ドリンク",starts_with("ドリンク")) -> kaoku1 kaoku1 %>% kable(align = "c",format = "html")
客番号 | メイン | サイド | ドリンク |
---|---|---|---|
1 | テリヤキバーガー\_500 | ポテト\_100 | コーラ\_100 |
2 | 月見バーガー\_600 | ポテト\_100 | オレンジ\_120 |
3 | ハンバーガー\_300 | オニオンフライ\_200 | オレンジ\_120 |
4 | ハンバーガー\_300 | NA\_NA | NA\_NA |
5 | テリヤキバーガー\_500 | サラダ\_300 | ウーロン茶\_150 |
pivot_longer()
で縦長にする
kaoku1 %>% pivot_longer(メイン:ドリンク,names_to="メニュー",values_to="詳細") ->kaoku2 kaoku2 %>% kable(align = "c",format = "html")
客番号 | メニュー | 詳細 |
---|---|---|
1 | メイン | テリヤキバーガー\_500 |
1 | サイド | ポテト\_100 |
1 | ドリンク | コーラ\_100 |
2 | メイン | 月見バーガー\_600 |
2 | サイド | ポテト\_100 |
2 | ドリンク | オレンジ\_120 |
3 | メイン | ハンバーガー\_300 |
3 | サイド | オニオンフライ\_200 |
3 | ドリンク | オレンジ\_120 |
4 | メイン | ハンバーガー\_300 |
4 | サイド | NA\_NA |
4 | ドリンク | NA\_NA |
5 | メイン | テリヤキバーガー\_500 |
5 | サイド | サラダ\_300 |
5 | ドリンク | ウーロン茶\_150 |
separate()
で戻す
kaoku2 %>% separate(col=詳細,into=c("種類","価格")) %>% kable(align = "c",format = "html")
客番号 | メニュー | 種類 | 価格 |
---|---|---|---|
1 | メイン | テリヤキバーガー | 500 |
1 | サイド | ポテト | 100 |
1 | ドリンク | コーラ | 100 |
2 | メイン | 月見バーガー | 600 |
2 | サイド | ポテト | 100 |
2 | ドリンク | オレンジ | 120 |
3 | メイン | ハンバーガー | 300 |
3 | サイド | オニオンフライ | 200 |
3 | ドリンク | オレンジ | 120 |
4 | メイン | ハンバーガー | 300 |
4 | サイド | NA | NA |
4 | ドリンク | NA | NA |
5 | メイン | テリヤキバーガー | 500 |
5 | サイド | サラダ | 300 |
5 | ドリンク | ウーロン茶 | 150 |
これで整然データになりました。