2014年10月26日日曜日

ggplotを使ったfor文で項目名を順番に変えていく

ggplot2でグラフを描く時に、データに使う項目名(具体的にはcsvの列名)を変えて同じ体裁のグラフを複数いっぺんに描きたいときがあって、調べてたら出来るようになったのでメモ。
(追記)reshapeパッケージのmelt.data.frameを使うほうが簡単かも。後述します。

例としてirisを使います。

names(iris) 

とすると、当然
 
[1] "Sepal.Length" "Sepal.Width"  "Petal.Length" "Petal.Width"  "Species" 

と表示されます。
ここで、x軸をSpeciesにして、y軸用データを"Sepal.Length" "Sepal.Width" "Petal.Length"にして、それぞれの項目でボックスプロットにしたグラフを描くことを目的とします。

aes_stringを使う方法

まず、使いたい項目名をxnamに入れます(xnamは任意)。
 
xnam<-c("Sepal.Length","Sepal.Width","Petal.Length")

ggplot関数で作図したプロットを入れるリストをつくります。
plots<-list()

通常のggplot関数ですと、aes()でx軸用データ、y軸用データを設定するのですが、変数にした文字列を読み込みたいとき(つまり、Sepal.Lengthを読み込みたいためにxnam[1]と書きたいとき)に aes(x=Species,y=xnam[1]) と書くと正しく描画されません。
したがって、aes_string()を使います。ただし、ここで注意が必要なのは、
 
aes(x=Species, y=Sepal.Length) 

で良かった指定が、
aes_string(x="Species", y="Sepal.Length") 

みたいにダブルコーテーションで囲ってやらないとダメなのです。
ということで、あとは以下のようにfor文を書きます。
 
j <- 1
for (i in 1:length(xnam)) {
    plots[[j]]<-ggplot(iris, aes_string(x="Species",y=xnam[i])) + geom_boxplot()
    j <- j+1
  }

  これで3つのプロットが出来たわけですが、1枚にいっぺんに描くには次のように書きます。
 
args <- c(plots, list(ncol=3, nrow=1))
do.call(grid.arrange, args)
grid.arrangeはgridExtraパッケージの関数です。問題なく実行されると以下の様なグラフが出力されるはずです。
なおargs, do.callの書き方は以下のサイトを参考にさせていただきました。多謝!
R - 可変長引数が最初にある関数に対する do.call() のやりかた - Qiita


(追記)melt.data.frameを使う方法

reshapeパッケージの関数です。超便利。
install.packages("reshape")
library(reshape)
iris2 <- iris[,-4] #Petal.Widthを削除(上の例に合わせてます)
iris2.melt <- melt.data.frame(iris2,id.vars="Species",variable_name="Region")
実行してやると、ほらこの通り。魔法みたい。
> head(iris2.melt)
  Species       Region value
1  setosa Sepal.Length   5.1
2  setosa Sepal.Length   4.9
3  setosa Sepal.Length   4.7
4  setosa Sepal.Length   4.6
5  setosa Sepal.Length   5.0
6  setosa Sepal.Length   5.4
列名のvalueはデフォルトで決まっているようなので後で変えたいときは以下のようなのを。
names(iris2.melt) <- c("Species","Region","Length")
で、プロット。
ggplot(iris2.melt,aes(Species,Length)) + geom_boxplot() + facet_wrap(~Region, scales="free_y") 
結果はこんな感じ。
以下を参考にさせていただきました。
data.frame を ggplot2 用に加工する - joker8phoenix's diary

2015年4月16日追記:reshapeで感動していたのも束の間、時代はreshape2を通り越して、tidyr + dplyr を使おうってことになっているらしい。時代にまったくついて行けてない初心者です。
参考:http://meme.biology.tohoku.ac.jp/students/iwasaki/rstats/reshape2.html