Pythonで情報利得を計算してみる
ジニ係数に引き続き、情報利得の関数も作ってみました。
ジニ係数については以下を参照ください、
以下の流れでご紹介
- 情報利得の簡単な説明
- 情報利得の実装
情報利得って
wikiによれば
カルバック・ライブラー情報量(カルバック・ライブラーじょうほうりょう、英: Kullback–Leibler divergence、カルバック・ライブラー・ダイバージェンス)とは、確率論と情報理論における2つの確率分布の差異を計る尺度である。情報ダイバージェンス(Information divergence)、情報利得(Information gain)、相対エントロピー(Relative entropy)とも呼ばれる。
http://ja.wikipedia.org/wiki/カルバック・ライブラー情報量
wiki冒頭にあるように、いろいろな呼び方があります。私はたまたま情報利得という呼び方を最初に知ったので、その呼び方に慣れていますが、内容を一番わかりやすく表現しているのは相対エントロピーではないかと思います。
Pythonで実装
まずは単一の状態でのエントロピーを計算する関数を実装します。
こいつをある変数に対して分割前の状態と分割後の各状態で計算して、その差分を見るのがデータ分析での情報利得の扱いですね。
# -*- encoding=utf-8 -*- import numpy import pandas from collections import Counter def entropy(vec): entropys = list() count = Counter(vec) countall = float(numpy.sum(count.values())) for item in count.items(): counteach = item[1] prob = counteach/countall entropyeach = -prob * numpy.log(prob) # print "%s : %f" %(item[0],entropyeach) entropys.append(entropyeach) entropy = numpy.sum(entropys) print "%s : %f" % (vec.name, entropy) return entropy
続いて、このentropyを呼び出して分割前の目的変数yのエントロピーと、あるカテゴリカル変数xで分割した後のエントロピーを比較します。この差分が正の方向に大きいほど、「xによる分割で各サブセット内のyに秩序が生じた」ことになるので、xは影響力のありそうな特徴量かな、となります。
def informationGain(x,y): # x,yともにカテゴリカル変数 root_ent = entropy(y) grouped = y.groupby(x) leaf_ent_0 = grouped.apply(entropy) leaf_weight = grouped.apply(len) / float(len(y)) leaf_ent = leaf_ent_0 * leaf_weight ig = root_ent - leaf_ent.sum() print "information gain : %f" %ig return ig
ついでにxが連続量の場合についても作ってみました。
厳密にはxについて積分が必要な気がしますが、簡易版として100分割して
離散化しています。
def informationGainNum(x,y, bins=100): # xが連続変数、yがカテゴリカル変数 root_ent = entropy(y) xname = x.name yname = y.name xy = pandas.concat([x,y], axis=1) xbins = pandas.cut(xy[xname], bins) # xbins = pandas.qcut(xy[xname], 10) grouped = xy[yname].groupby(xbins) leaf_ent_0 = grouped.apply(entropy) leaf_weight = grouped.apply(len) / float(len(y)) leaf_ent = leaf_ent_0 * leaf_weight ig = root_ent - leaf_ent.sum() print "information gain : %f" %ig return ig
では実際に使ってみます。
x = numpy.random.choice(["A","B","C"], 100) x = pandas.Series(x) y = numpy.random.choice([0,1], 100) y = pandas.Series(y) y.name = "testy" informationGain(x,y)
これを実行すると、以下のようになります。
testy : 0.692947 A : 0.693147 B : 0.690186 C : 0.692627 information gain : 0.001116
せば