2013/03/10

Rで二重箱ひげ図 (2軸箱ひげ図; 箱ひげ相関図) を描く

箱ひげ図
図1 単純な箱ひげ図
  • 数値データの分布を視覚的に示した図。
  • 単純な散布図に比べ、情報が整理されている。
  • 平均や分散ではなく、分位数を用いているため、分布形状が不明な(正規分布でない)データや、サンプル数が少ないデータ、また、外れ値を含んだデータの特徴をよく表す。
# 図1
> boxplot(x)
  1. 中央値 median
  2. 第1四分位 1st Quartile
  3. 第3四分位 3rd Quartile
  4. 四分位範囲 IQR: Interquartile Range
  5. ひげ Whisker
  6. 外れ値 Outlier
図2 カテゴリ(ファクター)ごとの箱ひげ図

カテゴリの有意性を判定するのに、分散分析 (ANOVA) 表がよく用いられるが、箱ひげ図による判定も優れている。

# 図2
> boxplot(formula=y~x)

二重箱ひげ図とは
図3 1カテゴリの単純な2重箱ひげ図
  • 二重箱ひげ図 (2軸箱ひげ図; 箱ひげ相関図) とは、通常の箱ひげ図を水平方向と垂直方向に描き、重ねあわせたものだ。
  • (x,y)の対データを箱ひげ図にすると考えればよい。
しかし、次のようなデータを、わざわざ二重箱ひげ図にする必要は無い。
x         y
111.1   37.5
107.2   32.3
100.5   24.0
103.9   33.0
...
このように対として観測したデータには、もっと相応しい解析方法がある。
二重箱ひげ図が活躍するのは、次のようなケースだ。
x= (111.2 97.2 100.5 94 107.7 ...)
y= (37.6 32.3 24.1 33.1 35.2 ...)
  • 別々に観察された2組のデータの相関を分析したい。
  • たとえば、身長と体重が個人ごとに対になったデータではなく、身長と体重を別個の集団で測定したデータだけがあって、その分析をしたい。

そんな分析に意味があるのだろうか?
実際、上記の1カテゴリでは、ほとんど得るものは無い。
図4 カテゴリを含む二重箱ひげ図
たとえば、
カテゴリ : 測定を行った場所、千葉県、茨城県、栃木県などの区分。
測定値x : 小学生の身長。
測定値y : 小学生の体重。
仮に、県によって、体型の差が有意にあるなら、カテゴリごとの平均身長と平均体重に一定の傾向が出る可能性がある。 しかしサンプルが少なかったり、非常に大きな子の突出したデータがあったりしたら、平均では何を見ているのかわからなくなる。 さらに、小学生という区分が広すぎて、同一カテゴリ内の学年差や個人差というノイズが大きすぎることも容易に予想できる。

実験室での測定や、計画的なアンケート調査であれば、こんなケースは実験計画の失敗と言える。 少なくとも小学生の身長と体重なら、対にして測定しなおすことが好ましい。

しかし、野生生物の観察や気象天文現象などでは、しばしば、異なる人、異なる日時の観察、観測データを組み合わせたおおらかな解析が要求される。 観測そのものが珍しい現象もあるし、データを集めることに膨大な費用がかかることも多いから。

また、制御されていない野生生物の観察では、時に極端な外れ値が発生する。 実験室ではないのだから、外れ値は、除外すべきゴミではなく、慎重に扱うべき、貴重なデータの一つだ。 ざっくりと分散分析にかけてしまうわけにはいかない。

二重箱ひげ図は、個別の対になっていないデータ、サンプルが少ないデータ、外れ値を含むデータ、の解析に道を開く。 荒っぽい言い方をすれば、駄目データに光を当てる統計ツールだ。

二重箱ひげ図を描くには、boxplotdou のソースを読み込んで使う。

boxplotdou() の使い方

配布元
http://code.google.com/p/cowares-excel-hello/wiki/boxplotdou_r
必要なソース
> source("boxplotdou.R")
> source("has.overlap.R")
動作テスト
> source("test.boxplotdou.R")
> test1()
...
とりあえず使う
> str(x)
'data.frame':   100 obs. of  2 variables:
 $ factor.x: chr  白 白 柏 印 印 印 印 印 つ ...
 $ obs.x   : num  12.81 9.09 9.03 10.89 9.67 ...
> str(y)
'data.frame':   50 obs. of  2 variables:
 $ factor.y: chr  柏 柏 柏 柏 柏 つ つ つ 牛 ...
 $ obs.y   : num  12.69 9.13 9.11 11.03 9.64 ...
上記のような、カテゴリ(ファクター)と観測値が対になったデータフレームを、x, y の2通り用意する。
> boxplotdou(x, y)
これで二重箱ひげ図が描かれる。
  • 箱ひげは、カテゴリごとに塗り分けられる。
  • ファクターの記号(文字)を図に描き入れるので、長い名称にせず、漢字1文字程度の省略名にした方が見やすい。
  • このようにして、別々に観察された obs.x と obs.y の間の関連性を、同一カテゴリ factor.x と factor.y による縛りのもとで解析することができる。
  • 計算は標準の boxplot() に依存しているので、計算値は boxplot() と同等になる。

描画オプション

boxed.whiskers=FALSE
TRUEにすると
ひげ部分を、通常のひげ形状でなく、外周を囲む四角の枠として描く。
ひげの重なり判定をしたい場合に使う。

outliers.has.whiskers=FALSE
TRUEにすると
外れ値にひげを描く。
外れ値を視覚的に目立たせたい場合に使う。

name.on.axis=TRUE
FALSEにすると
右と上の枠上にカテゴリ名を記載しない。

plot=TRUE
FALSEにすると
描画する代わりに、結果表を出力する。

verbose=FALSE
TRUEにすると
途中計算の過程を出力する。
主にデバッグ用途。

カテゴリをまとめる (condense)

condense=FALSE
condense.severity="iqr"
condense.once=FALSE

condense=TRUEにすると、
二重箱ひげ図上で近くにあるカテゴリを1つにまとめて描画する。
区別する意味のないカテゴリを集めることで、カテゴリのサンプル数を上げ、また、図を見やすくする。

condense.severityは、「近くにある」という判定基準を決める。

condense.severity="iqr"は、第1と第3四分位に囲まれた四角形が重なりを持つものを、「近い」と判定する。

condense.severity="whisker"は、ひげに囲まれた四角形が重なりを持つものを、「近い」と判定する。

condense.severity="iqr.xory"condense.severity="whisker.xory" のように、 .xory をつけると、x軸およびy軸のどちらか一方でも重なりを持つものを、「近い」と判定する。

condense.once=TRUEにすると、condense動作を1回だけ行う。FALSE では、集約結果を再判定し、判定が動かなくなるまで繰り返し処理を行う。主に、デバッグ用途。


テストデータによる二重箱ひげ図の挙動

x, y の相関が全くない場合
  • 相関が無い場合、互いに重複し、ランダムに並んだ図となる。
図5 test2 の結果
図6 test2 の結果 condense=T

x, y に強い相関があるが、選んだカテゴリによる差が無い場合
  • カテゴリ差が無いと互いに重複するので判定できない。
  • しかし相関が強い場合、その配置に一定の傾向が見られる。
図7 test3 の結果
図8 test3 の結果 condense=T

x, y に強い相関があり、いくつかのカテゴリで差がある場合
  • x, y, およびカテゴリに相関があれば、箱ひげの位置が x およびy 軸それぞれで有意に分離できる。
図9 test4 の結果
図10 test4 の結果 condense=T
図11 test4 の結果 condense=T,condense.severity="iqr.xory"

x, y に相関がなく、いくつかのカテゴリで差がある場合
  • x とカテゴリに相関があれば、x軸方向だけ分離した箱ひげになる。
図12 test5 の結果
図13 test5 の結果 condense=T
図14 test5 の結果 condense=T,condense.severity="iqr.xory"

No comments: