複数のカテゴリ変数同士の相関を一気に可視化する方法

複数のカテゴリ変数があって、それらの相関をみたいときクラメールの連関係数というのが便利です。

カテゴリ変数の間の相関をまとめた変数をざっくり取り出したいときは因子分析というのを使うことが多いと思いますが、ここでのテーマはその因子分析とかを適用する手前の「まずデータの雰囲気を見る」段階についてです。

データフレームagというのがあるとします。

> head(ag)
  A B C D E F G
1 1 0 2 2 1 2 1
2 0 0 3 2 0 0 2
3 0 0 1 2 0 0 1
4 1 1 3 2 1 1 3
5 1 1 1 1 0 2 2
6 2 0 3 3 0 3 3
> nrow(ag)
[1] 97009

reshape2パッケージを使うとカテゴリの値ごとにクロス集計できます。例えば、カラムAとBのカテゴリ値のクロス表は

library(reshape2)
> dcast(ag,A~B,length,value.var=1)
  A     0     1
1 0 15021  6357
2 1 27410 32172
3 2  8393  7656

となります。このクロス表に対してクラメールの連関係数を求めます。ここにRのコードがあるのでコピペします。

cramer.coe <- function(dat){
  row.sum <- apply(dat, 1, sum)
  col.sum <- apply(dat, 2, sum)
  row.length <- length(dat[,1])
  col.length <- length(dat[1,])
  my.sum = 0
  for(i in 1:row.length){
    for(j in  1:col.length){
      num <- dat[i,j]^2 / (row.sum[i] * col.sum[j])
      my.sum <- my.sum + num
    }
  }
  coe <- sqrt((my.sum - 1) / (row.length - 1))
  coe
}

matrixで与える必要があるので加工します。

dcast.coe <- function(dat,form) {
  d <- dcast(dat,form,length,value.var=1)
  d.m <- matrix(as.double(as.matrix(d[,2:ncol(d)])),nrow(d),ncol(d)-1)
  cramer.coe(d.m)
}
> d <- dcast.coe(ag,A~B)
[1] 0.1383269

値が出ました。カテゴリ変数AとBの間には相関がそれほどなさそうです。

さて、これをAからGまで自動的にやりたいです。それにはdcastの第二引数のformulaをプログラム的に作ってやる必要がありますが、formulaというRの組み込み関数を使えば、文字列→formulaの変換ができますので、pasteで文字列を作って渡せばOK.

cols1 <- names(az)
cols2 <- names(az)
df <- data.frame()
for (c1 in cols1) for (c2 in cols2) {
  t <- paste(c1,"~",c2)
  coe <- if (c1==c2) NA else dcast.coe(ag,formula(t))
  #cat(paste(t,coe,"\n"))
  df <- rbind(df,data.frame(c1=c1,c2=c2,coe=coe))
}

(cols1とcols2は同じでなくても大丈夫なので、カラムを2グループに分けて、それぞれのグループから1個ずつとりだしてペアを作ったときの相関を見る事もできます。)

さて、カラムAからGまでの各ペアについてクラメールの連関係数が求まりました。ggplot2で可視化します。

library(ggplot2)
p <- ggplot(df,aes(c1,c2))+geom_tile(aes(fill=coe),color="white")+
  scale_fill_gradient(low="white",high="steelblue")
print(p)

実行すると以下のようになります。

色の濃いところ(グレー以外)が連関係数の大きいところです。(A,E),(A,F),(B,E),(C,D)あたりが濃いですね。このあたりはまとめてモデル化を考えた方がよさそうかな、とかが見えて良い感じです。

これをベースに因子分析したりクラスターにまとめたり、独立な要素ごとに分解してモデリングしたりといったことが出来ますね。

質的変数のみを扱うやり方があまりググっても出てこなかったので書いてみた次第でした。上の例と同様なものでkaggle用に作ったソースをgistにおいてあります。