pythonで類似度の計算とか

研究でやった共起頻度とかの共起まわりの計算処理をツール化しようという計画。
pythonGUIを使ってInteractiveに仕上げる…予定。
とりあえずMeCabをインポート。mathも便利なので使う。

import sys
import MeCab
import math

形態素の処理の部分

accep_f=['感動詞','形容詞','動詞','名詞','未知語','フィラー']
accep_d=['サ変接続','一般','自立']

text=open('text.txt','r')
m = MeCab.Tagger('')

for line in text:
    node = m.parseToNode(line)
    id_doc+=1
    
    while node:
        N+=1
        if(node.feature.split(",")[0] in accep_f and
              node.feature.split(",")[1] in accep_d):
            freq_vector(node.surface,id_doc,line.count(node.surface))
        node=node.next

すごく楽。しているのはIDの付与と単語数のカウントと、単語ごとの文脈ベクトルを作ることぐらい。ちなみに前に作ったperl版だとこの辺で100行ぐらい消費。
文脈ベクトルfreq_vectorpythonの辞書で定義。numpyの行列でしようと思ったけどうまくいかず、結局そこに落ち着いた

def freq_vector(x,y,freq):
    vector.setdefault(x, {})[y] = freq

これで単語が行、文書が列の擬似的な行列が作れる
例:

文書1 文書2
りんご 1 1
みかん 2 0

参照はvector['単語']['文書']という感じで。
出力してみる

print '\n'.join('%s: %s' %i for i in vector.items())

こんな感じで出力されてくる

男性: {9: 1, 2: 1, 5: 1}
確認: {9: 1}
い: {1: 4}
コミュニケーション: {10: 1}
位置: {9: 1}
し: {11: 1, 1: 2, 2: 2, 3: 1, 9: 1}
する: {9: 1, 11: 1}
入れ: {6: 1}
自分: {9: 1, 11: 1}
あり: {1: 1, 3: 1}
ある: {5: 1}
仕事: {2: 1, 10: 1, 5: 1}
コーヒー: {6: 1}

{}の中は{文書ID: 出現数}となっていて、単語ごとに出現した文書とその出現数をカウントしている
これを使ってテキスト中の単語間の共起頻度や類似度などを計算することができる

def colocation(v1,v2):
    return sum(v1[i]+v2[i]-1 for i in v1 if i in v2)

def sim_cos(v1,v2):
    inner = sum(v1[i]*v2[i] for i in v1 if i in v2)
    denominator = math.sqrt(sum(v1[i]**2 for i in v1)*sum(v2[j]**2 for j in v2))
    return float(inner/denominator) if denominator !=0 else 0

def sim_simpson(v1,v2):
    numerator = sum(i in v1 for i in v2)
    denominator = min(len(v1), len(v2))
    return float(numerator/denominator) if denominator !=0 else 0

Print outすると

>>> print colocation(vector['コミュニケーション'],vector['仕事'])
1
>>> print sim_cos(vector['コミュニケーション'],vector['仕事'])
0.57735026919
>>> print sim_simpson(vector['コミュニケーション'],vector['仕事'])
1.0

これを見ると、解析したテキスト内で”コミュニケーション”と”仕事”という単語は1回共起していて、コサイン類似度で言えば0.58、シンプソン係数では1.0類似している

シンプソン係数が1になってしまっているけれども、テキストの量が少ないからでテキスト量が増えればコサイン類似度に近い値になる
まともな値を得たければ、どの類似度についてもある程度のテキスト量が必要になる

参考
http://sucrose.hatenablog.com/entry/2012/11/30/132803