「統計解析ログ/R作図」の編集履歴(バックアップ)一覧に戻る

統計解析ログ/R作図 - (2010/01/31 (日) 21:58:26) のソース

*R作図
このページでは、Rで作図する基本的な手順を紹介したいと思います。いい図はデータ解析を助けてくれますので、ぜひ自分の思い通りの図を描けるようになってください。

#contents

* Rで作図するメリット・デメリット
** メリット
- データを解析しながら作図できる
- 複数の図を描くときに自動化できる
- 様々な形式で図が出力可能(png, jpg, メタファイル, pdf, epsなどなど)
- 低水準作図を駆使すれば、フォーマットが決まっていない図も描ける(地図など)

** デメリット
- マウスで何か操作する訳ではないので、関数を知らないとどうにもならない
- 複雑な作図だとコードが長くなる
- 低水準作図で次々と要素を足していったときに、途中で間違えても戻れない

個人的には、複数の図が自動化ですぐにかける点と、低水準作図を駆使することでフォーマットにとらわれない図がかける点が特に便利だと思います。これらの点は、データを見る上で(ひいては統計解析する上で)データをよく見るために欠かせません。

ということで、私も昔はExcelで作図していましたが、Rで作図する方が研究にとっては&bold(){100倍ぐらい楽だ}と思っています。

なお、筆者の力量不足のため、このページではlatticeによる作図は取り扱いません。

* Rにおける作図手順
+ どんな図を描くかよく考えます。既成のフォーマットにとらわれる必要はありません。ノートにラフスケッチするのもいいでしょう。
+ 図を描くにあたり、データの形(並び方)が作図に適しているか考えます。何かしらの要因が横方向に展開しているデータの形式は好ましくありません。また、自動でいくつもの図を描くのであれば、split()などでデータを分割しておく必要があるでしょう。
+ 出来上がる図が、高水準作図で用意されている図で作成できそうか考えます。どうにも当てはまらない場合、高水準作図で空の空間だけ発生させます。
+ 低水準作図で細かいところまで仕上げます。
とにかく大事なのは、どういう図を描きたいのかよく考えることです。そしてその図は、既に見たことがある図でもいいですし、全く新しい図でもかまわないのです。自分が言いたいことをもっともよく表現してくれそうな図がどんな図か、よく考えましょう。

* 高水準作図
高水準作図は、「すでに形ができあがっている図を出力する作図」です。図の種類としては、

- plot(): 散布図
- pairs(): 対散布図(全ての2変数の組み合わせについて散布図を作成)
- boxplot(): 箱ひげ図(カテゴリーごとのデータのばらつきを見るのに有効)
- barplot(): 棒グラフ。Rコアチームの意図か、デフォルトではひどく見栄えの悪い関数
- pie(): 円グラフ
- scatterplot3d(): 三次元散布図。library(scatterplot3d)で呼び出せる

などがあります。

* 低水準作図関数
低水準作図は、図に細かく装飾をしていく作図です。これを駆使すると、一から新しい図を作図することもできます。

** 凡例を表示
legend()を使う。

例えば
> > d <- rnorm(100, 10, 5); e <- d + rnorm(100, 5, 2)
> > plot(y ~ x) #まず図の生成
> > legend("topleft", legend="x") #凡例を図に表示させる
legend("出力位置", legend="つけたい名前")という指定をしている。

2組の凡例(例えばxとy)を同時発生させる場合は、
> > plot(y ~ x)
> > legend("topleft", legend=c("x", "y"))
とする。単に名前の部分がベクトルで複数になっただけ。

さらに、2組の凡例で、かつ(シンボル テキスト)というような見せ方をしたい場合。
> > plot(y ~ x)
> > legend("topleft", legend=c("x", "y"), pch=c(15,19), col=c("yellow","purple"))
legend("出力位置", legend=c("xのラベル","yのラベル"), pch=c(xのシンボル,yのシンボル), col=c("xのシンボルの色","yのシンボルの色"))という指定をしている。


デフォルトでは凡例に枠がついてしまうが、これを消したい場合は、legend()の引数で
> > legend(......, bty="n")
とすればよい。


**特殊なフォントを使う
expression()を使う。

例えばplot()中でイタリック文字を使いたいとき、
> > plot(y ~ x, xlab=expression(italic("イタリック文字ににしたい文字")))
とすればよい。

数式も記述できる。
> > plot(y ~ x, xlab=expression(paste("RGR (mg ",mg^-1,year^-1,")"), ylab="")
expression内のpaste内で記述する。普通の文字にしたい部分は""でかこみ、数式処理をしたいところはそのまま記述する。今回は^で上付き処理をしている(下付きは[])。通常部分と数式部分は,で区切る。


**棒グラフにエラーバーを発生させる
-barplotとarrows関数を使う
-barplot2関数を使う

***barplot()の場合
> > y <- c(1,3,11,8,15) #値のベクトル
> > error <- c(0.1,0.3,1.1,0.8,1.5) #エラーバーの長さ(標準偏差とか)
> > location <- (0.2 + 1) * 1:5 - 1/2 #エラーバーを発生させる位置(x座標)。
最後のエラーバーの位置指定は一見よくわからない式だが、Rの棒グラフは棒グラフ間は0.2、棒グラフの太さは1がデフォルトである。棒グラフの中心にエラーバーを発生させるのであれば、x座標は最初必ず0.2あいて、それに棒グラフ1本が来て1が足され、そこから半分の0.5が引かれている。そして1:5で2本目、3本目...とどんどん位置を指定している。ちなみに名前は何でもよい。

というように、値そのもの、エラーバーの長さ、エラーバーのx軸の位置を指定するオブジェクトを生成しておいて、
> > barplot(y) #ここでまず棒グラフが生成される
> > arrows(location, y, location, y + error, angle=90)
(エラーバーの基部のx座標,基部のy座標,エラーバーの先端のx座標,先端のy座標,エラーバーの角度)という指定の仕方

これで棒グラフに上向きのエラーバーが生成される。もし下向きのも付け加えたいときは
> > arrows(location, y, location, y - error, angle=90)
とすればよい。

***barplot2()の場合
barplot2はgplotsというパッケージ内にある。

> > y <- c(1,3,11,8,15)
> > error <- c(0.1,0.3,1.1,0.8,1.5)
> > barplot2(y, plot.ci=T, ci.l=y-error, ci.u=y+error)
というように、barplot2 (値そのもの、エラーバーを作るか作らないか(Tで作るにしている)、エラーバーの下限値、エラーバーの上限値)
とすればよい。


**散布図に直線を当てはめる
lsfit()で回帰直線を生成し、abline()で散布図に結合する。
例えば
> > plot(x,y)  #まず散布図を生成
> > abline(lsfit(data$x, data$y)) #lsfit内で回帰直線を生成、#ablineで散布図に結合
とすればよい。

または、
> > model <- lm(y ~ x) #回帰分析の結果をmodelに結合
> > plot(x,y) #散布図の生成
> > abline(model) #modelに結合された回帰直線をablineによって散布図に結合


**対数軸で自由に軸幅設定
axis()を使う。

通常図の軸幅は
> > par(lab=c(*, *, 7))
によって指定する。前の二つで、x軸とy軸につける目盛の数を指定できる。最後の数字はラベルのサイズを指定するはずなのだが、どうやらRには移植されていないコマンドらしい。

ところが対数軸にすると、このグラフィックスパラメータは機能しない。そこで以下のようにする。
> > plot(x, y, xaxt="n", ...) #xaxt="n"で軸を書かないようにする。
> > axis(1, c(0.1,1.0,10.0,100.0)) #自分で軸を設定。
axis(軸の場所(1は図の下に軸をおけという意味(3が上、右が4、左が2)), c(に区切りを挿入する場所))である。


**軸目盛ラベルの角度変更
軸目盛ラベルの角度は通常グラフィックスパラメータlas=*を高水準作図関数内の引数として記述する。
- las=0 #各軸(x,y)に対して平行にラベルが出現
- las=1 #軸に関わらず全て水平にラベルが出現
- las=2 #各軸に対して垂直にラベルが出現
- las=3 #軸に関わらず全て垂直にラベルが出現

さらに、角度を詳細に指定して描きたい場合がある。この場合、一度ラベルなしの軸を描き、その上に低水準作図関数text()を利用してラベルを挿入する。ただしtext()で今回のように欄外に文字を発生させる場合、あらかじめ欄外に文字を書いてもよいという指定をする必要がある。以下ではboxplotでの作成例。

> > par(xpd=T) #図の外に文字を書くことを許可する指定
> > boxplot(column1,column2,column3, xaxt="n") #xaxt="n"で軸を書かないように
> > axis(1,at=1:*,labels=F) # *は欲しい目盛の数(何個目盛を打つか)、labels=Fは目盛ラベルを表示しない指定
> > x <- 1:* # 目盛ラベルのx座標の指定、*は欲しい目盛の数
> > y <- rep(-5,*) #目盛ラベルのy座標の指定、-5はグラフの値によって適時修正、*は欲しい目盛の数
> > text(x,y,c("A","B",...), srt=**, adj=1)
text()内の説明:x,yはそれぞれ先ほどの位置を指定する変数、c()は実際に入力したい目盛ラベルの名称が入ったベクトル、srt=**が本題の、目盛ラベルの角度を指定するパラメータ、adj=1はラベルを右揃えにするパラメータ(ラベルの角度によってadj=0左揃え、adj=0.5中央揃えのほうが見栄えがよいときがあります)

* カテゴリーごとにシンボルの異なる図を描く
カテゴリーを数字として扱うこと、数字で色やシンボルの形が指定できるのがポイントです。具体例を以下で示します。
> > e <- rnorm(100, 10, 5) #架空データの生成
> > f <- d + rnorm(100, 5, 2) #同上
> > g <- rep(LETTERS[1:4], each=25) #同上
> > d <- data.frame(e, f, g) #データフレーム化
> > plot(f ~ e, d) #普通に描画すると、全てのカテゴリーが同じシンボルになってしまう
>
> > plot(f ~ e, pch=as.numeric(g), d) #カテゴリーごとにシンボルが異なる

** as.numeric()を使いこなす
as.numeric()は文字列だろうが無理矢理数字にしてしまう関数です(数字はアルファベットの速い順から1、2、......とつきます)。これをカテゴリー変数にすることで、各カテゴリーごとに異なる数字がシンボルの形を示す引数pchや色を示す引数colに投入されます。

なので、色も同様に変えられます
> > plot(f ~ e, pch=as.numeric(g), col=as.numeric(g), d)

** 描画するシンボルや色を指定したい!
as.numeric()を使うと確かにデータにあわせてシンボルや色は変えられますが、基本的には1から順に番号が振られるので、必ずしも思い通りのシンボルや色になりません。こういう時には、事前にシンボルや色を指定しておきます。

> > iro <- c("black", "red", "blue", "green")
> > katachi <- c(0, 1, 15, 16) #番号によってどのようなシンボルが出力されるかはlibrary(Hmisc) ; show.pch()を見てください。
> > plot(f ~ e, pch=katachi[as.numeric(g)], col=iro[as.numeric(g)], d)

さて、上記のコマンドは何を意味しているのでしょうか?ベクトルの性質を思い出してみましょう。

ベクトルはある一つながりのデータです。

* 複数の図を自動で描く
先ほどは異なるカテゴリーのデータを同一の図に描画しました。今度は、カテゴリーごとに図を描きます。

といっても、一つ一つの図のコマンドを書いていたのではコードが膨大になり、また間違いが発覚した際に直す箇所も複数生じてしまいます。こういう時は、for()を使って自動化することを考えます。

このように、複数の図を自動で描く場合の基本的な手順は以下のようになります。

- 図を何行×何列で表示させるのか決める
- データをsplit()で&bold(){カテゴリーごとに分割}する
- for()で、カテゴリーごとの図の描画を全カテゴリー分繰り返す

では、以下で実際例を見ていきましょう。

** 図のレイアウト
図を何行×何列で表示させるのか指定する方法としては、
- par(mfrow=c(行数, 列数))
- layout()
の2つの方法があります。図を描く順番等を特に考える必要がないなら前者でいいでしょう。

*** layout()で自由な図の配置
layout()は、何番目の図をどこに描くかを数字で指定します。そのため、例えばある図だけ2行にわたって表示させたり、4カテゴリー目の図を1番最初に表示させたいなど、不規則な図の表示をさせるときに使います。例えば、
> 1番目の図   4番目の図
> 2番目の図   3番目の図

というような配置にしたければ、
> > layout(matrix(c(1, 4, 2, 3), ncoL=2, byrow=TRUE))
と指定します。matrix()はその名の通り行列を作る関数で、ncolは行列の列数、byrow=TRUEにすると、c()で投入した文字が行方向から埋めるように指定することになります。

別の例を見てみましょう。
> 1番目の図   4番目の図   3番目の図
> 2      番      目      の      図

というような配置にしたければ、
> layout(matrix(c(1, 4, 3, 2, 2, 2), ncol=3, byrow=TRUE))
と指定します。2番目の図が他の図3つ分のスペースに広がって表示させるために、2を3回指定しています。


** 相性抜群のsplit()とfor()
図のレイアウトが決まったら、カテゴリーごとに図を描画します。その際の基本的な考え方は、

> データをカテゴリーごとに分割し、カテゴリーごとのデータフレームを使って図を描く作業を全カテゴリー分繰り返す
となります。


** 例外処理


** 図全体に対する装飾