元のページ
ステージ3-3: 潜在的意味インデキシング(LSI)の例 (情報工学実験 3 : データマイニング班)
目次
想定環境
- OS: Mac OS X 10.8.x (10.7.x以降であれば同じ方法で問題無いはず)
- Python: 2.7.x
- Mercurial: 2.2
- numpy: 1.9.0.dev (numpy.version)
- NLTK: 2.0.4 (nltk.__version__)
- MeCab: 0.996 (MeCab.VERSION)
cosine類似度による特徴ベクトルの類似度確認
# データ準備(前回の続き)
from prettyprint import pp
docs = []
docs.append(u"会場には車で行きます。")
docs.append(u"会場には自動車で行きます。")
docs.append(u"会場には自転車で行きます。")
docs.append(u"お店には自転車で行きます。")
data = [[1, 0, 0, 0, 1, 1], [1, 0, 1, 0, 1, 0], [1, 0, 0, 1, 1, 0], [0, 1, 0, 1, 1, 0]]
# 型を行列に変換
# 単に特異値分解や次元削減するだけならそのままの文書行列を用いても良いが、
# 「単語(codebook)の視点から重要な特徴軸を抽出したい」ので、
# 以下では転置行列を処理していく。
import numpy as np
mat = np.matrix(data)
mat_T = mat.T
#行列の指定行indexをリストに変換
def matTolist(mat, index):
#return mat[index].tolist()[0]
return np.array(mat[index]).reshape(-1,).tolist()
# cosine類似度
def cosine_similarity(vec1, vec2):
u'''コサイン類似度。
vec1, vec2 は同次元の特徴ベクトル(リスト型)。
文章の類似度を測るために使われる指標の一つ。
同一ベクトルであれば類似度=1(最大値)。
全く異なる場合は類似度=0(最小値)。
>>> len(vec1) == len(vec2)
True
'''
import math
numerator = sum([vec1[x]*vec2[x] for x in range(len(vec1))])
sum1 = sum([vec1[x]**2 for x in range(len(vec1))])
sum2 = sum([vec2[x]**2 for x in range(len(vec2))])
denominator = math.sqrt(sum1) * math.sqrt(sum2)
if not denominator:
return 0.0
else:
return float(numerator) / denominator
# 初期特徴ベクトル(mat)で類似度を確認。
def printMatSim(mat):
for i in range(len(mat)):
str = ""
str += "d%d:" % (i)
#j = i+1
j = 0
while j < len(mat):
str += "%f, " % (cosine_similarity(matTolist(mat,i),matTolist(mat,j)))
j = j+1
print str
pp(docs)
printMatSim(mat)
単語・文書行列を特異値分解
# numpy を使って特異値分解
import numpy as np
U, s, V = np.linalg.svd(mat_T, full_matrices=False)
U.shape, s.shape, V.shape
# -> U.shape[1], s.shape[0], V.shape[0] のランクを下げることで近似可能。
# 以下では取りあえず近似せずにそのまま元の行列を再構築。
S = np.diag(s)
mat_T_svd = np.dot(U, np.dot(S, V))
np.allclose(mat_T, mat_T_svd)
#-> True
単語・文書行列をランク削減して近似
# 元のランクは4(s.shape[0]=4)。
# これをランクk=2に削減して近似してみる。
k = 2
print u"(ランクk=%d) 累積寄与率=%f" % (k, sum(s[:k]) / sum(s))
S = np.zeros((len(s),len(s)))
S[:k, :k] = np.diag(s[:k])
mat_T_rank2 = np.dot(U, np.dot(S, V))
pp(docs)
print "元の行列における類似度"
printMatSim(mat)
print "近似した行列における類似度"
printMatSim(mat_T_rank2.T)
参考サイト一覧