Edited at

素人の言語処理100本ノック:88

More than 1 year has passed since last update.

言語処理100本ノック 2015の挑戦記録です。環境はUbuntu 16.04 LTS + Python 3.5.2 :: Anaconda 4.1.1 (64-bit)です。過去のノックの一覧はこちらからどうぞ。


第9章: ベクトル空間法 (I)


enwiki-20150112-400-r10-105752.txt.bz2は,2015年1月12日時点の英語のWikipedia記事のうち,約400語以上で構成される記事の中から,ランダムに1/10サンプリングした105,752記事のテキストをbzip2形式で圧縮したものである.このテキストをコーパスとして,単語の意味を表すベクトル(分散表現)を学習したい.第9章の前半では,コーパスから作成した単語文脈共起行列に主成分分析を適用し,単語ベクトルを学習する過程を,いくつかの処理に分けて実装する.第9章の後半では,学習で得られた単語ベクトル(300次元)を用い,単語の類似度計算やアナロジー(類推)を行う.

なお,問題83を素直に実装すると,大量(約7GB)の主記憶が必要になる. メモリが不足する場合は,処理を工夫するか,1/100サンプリングのコーパスenwiki-20150112-400-r100-10576.txt.bz2を用いよ.



88. 類似度の高い単語10件


85で得た単語の意味ベクトルを読み込み,"England"とコサイン類似度が高い10語と,その類似度を出力せよ.



出来上がったコード:


main.py

# coding: utf-8

import pickle
from collections import OrderedDict
from scipy import io
import numpy as np

fname_dict_index_t = 'dict_index_t'
fname_matrix_x300 = 'matrix_x300'

def cos_sim(vec_a, vec_b):
'''コサイン類似度の計算
ベクトルvec_a、vec_bのコサイン類似度を求める

戻り値:
コサイン類似度
'''
norm_ab = np.linalg.norm(vec_a) * np.linalg.norm(vec_b)
if norm_ab != 0:
return np.dot(vec_a, vec_b) / norm_ab
else:
# ベクトルのノルムが0だと似ているかどうかの判断すらできないので最低値
return -1

# 辞書読み込み
with open(fname_dict_index_t, 'rb') as data_file:
dict_index_t = pickle.load(data_file)

# 行列読み込み
matrix_x300 = io.loadmat(fname_matrix_x300)['matrix_x300']

# 'England'とのコサイン類似度算出
vec_England = matrix_x300[dict_index_t['England']]
distances = [cos_sim(vec_England, matrix_x300[i])
for i in range(0, len(dict_index_t))]

# 上位10件を表示
index_sorted = np.argsort(distances)
keys = list(dict_index_t.keys())
for index in index_sorted[-2:-12:-1]: # トップに来る自分自身は除く
print('{}\t{}'.format(keys[index], distances[index]))



実行結果:


実行結果

Scotland    0.6780631362432838

Australia 0.6439496692044923
Wales 0.6352223096061712
Italy 0.5993389833593241
Spain 0.5810143958505265
France 0.5711030646029182
Japan 0.5709618229888032
Germany 0.5377148103064543
Ireland 0.5374312543293124
Europe 0.4868884673753479


実行結果について

結果を見ると国名が並んでいるので、「England」が国であることは特徴として捉えているようです。また、「Scotland」や「Wales」や「Ireland」といったイギリスの国がTop10に入ってきたのも驚きです。

文章を構文解析したり同義語辞書を使ったりしている訳でもなく、単純にその単語の周辺で使われる文脈語をベクトル化しただけで、ここまでヒトの感覚に似た単語を提示できるのは、いろいろな可能性を感じさせてくれて面白いですね。

 

89本目のノックは以上です。誤りなどありましたら、ご指摘いただけますと幸いです。


実行結果には、100本ノックで用いるコーパス・データで配布されているデータの一部が含まれます。この第9章で用いているデータのライセンスはクリエイティブ・コモンズ 表示-継承 3.0 非移植日本語訳)です。