DOING THINGS RIGHT

彩りのある生産的な日々を

脱・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で挿入できます。

このパッケージがすごい2014:magrittr

パイプライン記述は見やすくかつコードの発想が容易になり、見通しの良い記述の手助けをしてくれます。

次からは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") ##回帰モデル「線形」を指定

f:id:syumituduri:20201018173118p:plain

ちなみに、軸や塗りわけキー指定の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")

f:id:syumituduri:20201018173348p:plain

ヒストグラム

ggplot(iris,aes(x=Petal.Length,fill=Species,))+
  geom_histogram(position="dodge")

f:id:syumituduri:20201018173220p:plain

箱ひげ図、バイオリンプロット

ggplot(iris,aes(x=Species,y=Petal.Width))+
  geom_boxplot(fill="grey70")+ ##重ねた時にも見やすい色を指定しておく
  geom_violin(col="orange",fill="orange",alpha=0.5)

f:id:syumituduri:20201018173208p:plain

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
  1. 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
  1. 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
  1. 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

これで整然データになりました。