私の目標は、次のテキストドキュメント間のKL距離を計算することです。
1)The boy is having a lad relationship
2)The boy is having a boy relationship
3)It is a lovely day in NY
Numpyを簡単に適用するために、まずドキュメントをベクトル化しました
1)[1,1,1,1,1,1,1]
2)[1,2,1,1,1,2,1]
3)[1,1,1,1,1,1,1]
次に、テキスト間のKL距離を計算するために次のコードを適用しました。
import numpy as np
import math
from math import log
v=[[1,1,1,1,1,1,1],[1,2,1,1,1,2,1],[1,1,1,1,1,1,1]]
c=v[0]
def kl(p, q):
p = np.asarray(p, dtype=np.float)
q = np.asarray(q, dtype=np.float)
return np.sum(np.where(p != 0,(p-q) * np.log10(p / q), 0))
for x in v:
KL=kl(x,c)
print KL
上記のコードの結果は次のとおりです:[0.0, 0.602059991328, 0.0]
。テキスト1と3は完全に異なりますが、それらの間の距離は0ですが、関連性の高いテキスト1と2の距離は0.602059991328
です。これは正確ではありません。
KLに関して私が正しくやっていないことを誰かが知っていますか?あなたの提案に感謝します。
別の答えを追加するのは嫌ですが、ここには2つのポイントがあります。まず、Jaimeがコメントで指摘したように、KL発散(または距離-以下のドキュメントによると、同じです)は、確率分布間の差を測定するように設計されています。これは基本的に、関数に渡すものは2つの配列のようなものであり、それぞれの要素の合計が1になることを意味します。
第二に、scipyは明らかにこれを実装しており、情報理論の分野により関連した命名スキームを使用しています。関数は「エントロピー」です。
scipy.stats.entropy(pk, qk=None, base=None)
http://docs.scipy.org/doc/scipy-dev/reference/generated/scipy.stats.entropy.html
ドキュメントから:
QkがNoneでない場合は、相対エントロピー(Kullback-Leibler発散またはKullback-Leibler距離とも呼ばれます)S = sum(pk * log(pk/qk)、axis = 0)を計算します。
この関数の利点は、合計が1にならない場合に、渡すベクトルを正規化することです(ただし、渡す配列、つまりデータからの構築方法に注意する必要があります)。
これがお役に立てば幸いです。少なくともライブラリが提供しているので、独自にコーディングする必要はありません。
KLの概念を理解するために少しグーグルした後、あなたの問題はベクトル化によるものだと思います。異なる単語の出現数を比較しているのです。列インデックスを1つの単語にリンクするか、辞書を使用する必要があります。
# The boy is having a lad relationship It lovely day in NY
1)[1 1 1 1 1 1 1 0 0 0 0 0]
2)[1 2 1 1 1 0 1 0 0 0 0 0]
3)[0 0 1 0 1 0 0 1 1 1 1 1]
次に、kl関数を使用できます。
自動的に辞書にベクトル化するには、 リスト内の要素の頻度をカウントする方法 (collections.Counter
はまさにあなたが必要とするものです)。次に、辞書のキーの和集合をループして、KL距離を計算できます。
潜在的な問題は、NP KLの定義にある可能性があります。式についてはウィキペディアのページをお読みください: http://en.wikipedia.org/wiki/Kullback%E2%80% 93Leibler_divergence
(p-q)にログ結果を掛けることに注意してください。 KLの式によれば、これはp:のみである必要があります。
return np.sum(np.where(p != 0,(p) * np.log10(p / q), 0))
それは役立つかもしれません...