ビジネスと技術の狭間で

データを活用して生きていく

Maximal Information Coefficientの使い方

たまには技術系の話も書いてみます。

水準数が少ない変数に対して
Maximal Information Coefficient(MIC)を計算する場合は注意が必要という話です。

MICはだいぶ昔に話を聞いて便利そうだなーと思っていたのですが
これまで実際に使う機会はありませんでした。


www.slideshare.net


使う機会がなかった理由は
基本的に私は初期の段階からモデルを意識してアプローチすることが多く、
データマイニング」的な機械的な関係性抽出をあまり行わないからだと思います。
また、もしそういうことを行う場合は
機械学習のモデルを作って特徴量重要度を見ることが多かったです。

今回はたまたま「機械学習」というワードを使わず
相関係数」の一種ということで話を済ませた方が良さそうな状況だったので
Rの{minerva}を使ってみることにしました。


使う前の私の認識は以下でした。
・出力される値は0~1となり、完全な関連がある場合は1となる。
・連続変数でも離散変数でも離散化することになるので気にせず使える。

しかし実際に使ってみると、離散変数の場合は完全に一致していても
出力が1にならない場合があることに気付きました。

> library(minerva)
> 
> set.seed(1)
> x1 <- rpois(10000,1)
> table(x1,x1)
   x1
x1     0    1    2    3    4    5    6    7
  0 3700    0    0    0    0    0    0    0
  1    0 3599    0    0    0    0    0    0
  2    0    0 1862    0    0    0    0    0
  3    0    0    0  653    0    0    0    0
  4    0    0    0    0  161    0    0    0
  5    0    0    0    0    0   22    0    0
  6    0    0    0    0    0    0    2    0
  7    0    0    0    0    0    0    0    1
> mine(x=x1,y=x1)$MIC
[1] 0.9914476

当然ですが、19,20世紀に開発された
Pearson, Spearman, Kendallの相関係数は1となります。

> cor(x1,x1,method="pearson")
[1] 1
> cor(x1,x1,method="spearman")
[1] 1
> cor(x1,x1,method="kendall")
[1] 1

また、上記のケースではMICでも1に近い値となっていましたが
下記の様に0に近い値になることもあります。これは困ります。

> set.seed(1)
> x2 <- rpois(10000,0.01)
> table(x2,x2)
   x2
x2     0    1
  0 9904    0
  1    0   96
> mine(x=x2,y=x2)$MIC
[1] 0.07812958

当初、アルゴリズムのパラメータの設定が原因なのではないかと思ったのですが
それは本質的ではありませんでした。
このようなことが起こるのは、MICで計算している相互情報量の性質に依るからです。


MICのアルゴリズムを簡単に説明すると
2つの変数に対して様々な離散化を行って相互情報量を計算した上で
最大の相互情報量を出力するというものです。
(正確には出力が1を超えないようにするため
 離散化した水準数での補正がかかります。)

直感的な理解として
相互情報量は2つの変数間で共有する情報量を表しているため
情報量の少ない方の変数の情報量が相互情報量の上限となります。

加えて、離散化した変数の情報量は水準間で全く偏りがないときに最大となり
1つの水準に全てが集中しているときに最小(=0)となります。

つまり、離散化した変数がどちらかでも偏っている場合は
相互情報量は小さい値になってしまいます。

連続変数の様に水準数が多い変数であれば
偏りの少ない離散化を行える可能性が高くなるため問題はありませんが、
上記で見たような水準数の少ない変数については
離散化のバリエーションが少なくなるため
強い関連があってもMICが大きくならない場合があるということです。


長々と書いてきましたが、これを改善するのは簡単で
水準間の差よりも小さなノイズを加えて水準数を増やしてあげれば良いです。

> set.seed(1)
> noise <- runif(10000,min=-0.1,max=0.1)
> mine(x=x2+noise,y=x2+noise)$MIC
[1] 1

ノイズを加えたことでMICが大きく下がることはない気がしていますが、未検証です。
悪影響が小さいのであれば、アルゴリズム側で吸収してくれると嬉しいですね。


MICの詳しい計算手続きについては以下の資料が分かりやすかったです。
http://lectures.molgen.mpg.de/algsysbio12/MINEPresentation.pdf
この資料はこちらで知りました。ありがとうございます。

誤解等あれば教えていただけると幸いです。