別棟備忘録4

*

Doc2Vecを用いた分散表現のコード例

   

概要

日本語の文章群に対してDoc2Vecを使って「分散表現」してみる備忘録。pythonを使って、文章をベクトルで表します。

対象として使う文章群など、「分かち書き」のあたりまではこちらのエントリと同じなので、参照のこと。

pythonのコード

import numpy as np
import MeCab
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt

with open(r"C:\Users\********\Desktop\gakusyu_shoken.csv",encoding="utf-8") as f:
    reader = csv.reader(f)
    l = [row for row in reader]
    
print(type(l))

arr = np.array(l)
print(type(arr),np.shape(arr))

arr[0,0] = 'index'
arr_1 = arr.T
#print(arr_1[1])

wa  = MeCab.Tagger ("-Owakati  -u C:/Users/********/Desktop/shoken.dic")

l_2 = []
l_2.append('str_waka')

for i in range(916):
   l_2.append(wa.parse(arr_1[1][i+1])) 

arr_waka_str = np.array(l_2)

arr_data = np.c_[arr_1[0], arr_waka_str]
print(np.shape(arr_data))

sentences = []
for text in arr_data.T[1]:
    text_list = text.split(' ')
    sentences.append(text_list)

#print(sentences[10])


from gensim.models.doc2vec import Doc2Vec, TaggedDocument
documents = [TaggedDocument(doc, [i]) for i, doc in enumerate(sentences)]
model = Doc2Vec(documents, vector_size=1600, window=8, min_count=2, epochs=20, dm=0)
model.save("./shoken_str_02.model")
print("***model builded***")

sentence_num = 500
print(arr[sentence_num])
print("**********************以下類似文*************************")
for p in model.docvecs.most_similar(sentence_num):
    print(arr[p[0]])

print("sentence_no:", sentence_num)
plt.imshow(model.docvecs[sentence_num].reshape(40,40))
plt.colorbar()
plt.show()

print("sentence_no:545")
plt.imshow(model.docvecs[545].reshape(40,40))
plt.colorbar()
plt.show()

print("sentence_no:1")
plt.imshow(model.docvecs[1].reshape(40,40))
plt.colorbar()
plt.show()

print(model.docvecs.most_similar(sentence_num))

vectors=[]
for i in range(916):
    vectors.append(model.docvecs[i])
plt.imshow(vectors)
plt.colorbar()
plt.show()

 

要点
model = Doc2Vec(documents, vector_size=1600, window=8, min_count=2, epochs=20, dm=0)
ここでは、1600次元でベクトル化しています。おそらく、多すぎると思いますが、ちょっと多めにとりたかったのと、40×40の図にしたかったのと。
min_countは、最低2回登場する単語を語彙として採用することを意味しているらしい。epochs=20は学習の回数 dm=1ならPV=DMで0ならPV-DBOWで学習する

 

アウトプットに関して

今回は、500番目の文章「授業態度は良好であり、サイエンス化学や体育など実技実習系の科目に対して特に積極的な取り組みを見せた。」に類似する文章を捜索している。
for p in model.docvecs.most_similar(sentence_num): print(arr[p[0]])
の部分のprint結果より、類似度が高いと判断された順に、

[‘545’ ‘授業態度は良好であり、サイエンス生物や体育など実技実習系の科目において、特に積極的な取り組みを見せた。’]
[‘435’ ‘学習意欲があり、授業態度はたいへん真面目である。体育や書道など、実技を伴う科目の成績がたいへん優秀である。’]
[‘318’ ‘文章表現力や読解力に優れたものを持ち、英文読解に関する問に対しては当を得た回答をする。’]

であった。図で確認すると、500番目と545番目は

こんな感じで「分散表現」でベクトル化されていることがわかる。確かに、似ている。類似度0.9999603033065796!
しかし、[‘435’ ‘学習意欲があり、授業態度はたいへん真面目である。体育や書道など、実技を伴う科目の成績がたいへん優秀である。’]ってのはそんなに500番目と似てるかな?
…と思ったところでちょっと嫌な予感。試しに類似度が高い候補として挙げられていない文章#1:「授業に対して真面目に取り組み、特に理科に興味関心が高く優れた成績を修めた。また、運動能力に優れ、いろいろなスポーツを上手に行うことができる。」のベクトルを確認すると…
sen1
そう。500や、545とこれもそっくりであることが判明。
さらに試しに全ての文章のベクトルを1つの図にしてみると…
sen_all
さながらバーコード。つまり、要録所見文は全て似ている、と。(今回のように学習すると、少なくとも。)
類似度でいうと、0.9999**の5桁目からの差異を比べるような状況になっていることが判明したということです。

 - Python, stringDistance