練習問題2の解答例¶
上の例では直感に合うような結果はなかなか得られませんでした。その原因は以下であると仮定します。
- 対象としたコーパスのサイズが小さい。
- ユークリッド距離は単語の出現回数に影響を受けやすい。
この仮定に基づいて、コーパスサイズを大きくし(2016年のwikipediaから10000文)、類似度の計算にコサイン類似度を採用してみてください。このようにすると若干ですが、直感に合うような結果が得られるようになると思います。このデータは、2016年時点のwikipediaから10000文を抜粋したもので、文が改行で分けられ、個々の文に番号が振られ、アルファベット順に並んでいます。
In [1]:
# テキストの読み込み
f = open("../samples/eng_wikipedia_2016_10K-sentences.txt","r")
text = f.read()
In [2]:
import re
# テキストを改行で分ける。
text = text.split("\n")
# なぜか文の最後に数字の列(1942など)を登録してくれないので、
# 数字の列が最後にある文は削除
text2 = []
for i in text:
obj = re.search("¥d¥.$",i)
if not obj:
text2.append(i)
In [3]:
# 文番号を削除
text3 = []
for i in text2:
s,t = i.split("\t")
text3.append(t)
In [4]:
# 再度文字列に変換
text = " ".join(text2)
In [5]:
# 単語とそのIDの辞書を作成する。
# 使用するパッケージ
from nltk import word_tokenize
import numpy as np
# 単語分割
words = word_tokenize(text.lower())
# 単語にidをふって辞書を作る
# idがkeyでwordがvalueのディクショナリ
# wordがkeyでidがvalueのディクショナリ
word_to_id = {}
id_to_word = {}
# 単語分割したテキストからword_to_id, id_to_wordを作成する
for word in words:
if word not in word_to_id:
new_id = len(word_to_id)
word_to_id[word] = new_id
id_to_word[new_id] = word
- このデータは文単位で分割されているので、文ごとに処理します。
In [6]:
vocab_size = len(word_to_id)
co_matrix = np.zeros((vocab_size,vocab_size),dtype=np.int32)
window_size = 1
for i in text2:
L = []
words = word_tokenize(i)
for w in words:
L.append(word_to_id[w.lower()])
for idx,word_id in enumerate(L):
for j in range(1, window_size + 1):
left_idx = idx - 1
right_idx = idx + 1
if left_idx >= 0:
left_word_id = L[left_idx]
co_matrix[word_id,left_word_id] +=1
if right_idx < len(words):
right_word_id = L[right_idx]
co_matrix[word_id,right_word_id] +=1
In [7]:
# scipyのimport
import scipy.spatial.distance as dis
- 以下で示すように、"book"と"computer"と"bicycle"の関係はWord-netで示される類似度に近い、あるいは、直感に近い結果が得られます。
- また、"pork"と"pig"、"car"と"automobile"の類似度が1となっていて、かなり妥当な結果と言えます。
In [8]:
dis.cosine(co_matrix[word_to_id["book"]], co_matrix[word_to_id["computer"]])
Out[8]:
np.float64(0.29859492016274536)
In [9]:
dis.cosine(co_matrix[word_to_id["book"]], co_matrix[word_to_id["bicycle"]])
Out[9]:
np.float64(0.46714150842553825)
In [10]:
dis.cosine(co_matrix[word_to_id["computer"]], co_matrix[word_to_id["bicycle"]])
Out[10]:
np.float64(0.6464466094067263)
In [11]:
dis.cosine(co_matrix[word_to_id["pork"]], co_matrix[word_to_id["pig"]])
Out[11]:
np.float64(1.0)
In [12]:
dis.cosine(co_matrix[word_to_id["car"]], co_matrix[word_to_id["automobile"]])
Out[12]:
np.float64(1.0)