言語処理100本ノック2020 第7章 単語ベクトル

はじめに

言語処理100本ノック2020

言語処理100本ノックは東北大学が公開している自然言語処理の問題集です。

とても良質なコンテンツで企業の研修や勉強会で使われています。

そんな言語処理100本ノックが2020年に改定されてました。昨今の状況を鑑みて、深層ニューラルネットワークに関する問題が追加されました。(その他にも細かい変更があります)

この記事では、言語処理100本ノック2020にPythonで取り組んでいきます。

他にも色々な解法があると思うので、一つの解答例としてご活用ください!

全100問の解説に戻る

単語の意味を実ベクトルで表現する単語ベクトル(単語埋め込み)に関して,以下の処理を行うプログラムを作成せよ.

60. 単語ベクトルの読み込みと表示

Google Newsデータセット(約1,000億単語)での学習済み単語ベクトル(300万単語・フレーズ,300次元)をダウンロードし,”United States”の単語ベクトルを表示せよ.ただし,”United States”は内部的には”United_States”と表現されていることに注意せよ.

コード

gensimPythonのライブラリでトピックモデルやNLPの用途で利用されます。この記事ではgensimを使って学習済み単語ベクトルを扱おうと思います。

1
2
3
import gensim
model = gensim.models.KeyedVectors.load_word2vec_format('GoogleNews-vectors-negative300.bin', binary=True)
model['United_States']

61. 単語の類似度

“United States”と”U.S.”のコサイン類似度を計算せよ.

コード

similarityを利用します。

1
model.similarity('United_States','U.S.')

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

“United States”とコサイン類似度が高い10語と,その類似度を出力せよ.

コード

most_similarを利用します。デフォルトで上位10件を返却します。

1
model.most_similar('United_States',topn=10)

63. 加法構成性によるアナロジー

“Spain”の単語ベクトルから”Madrid”のベクトルを引き,”Athens”のベクトルを足したベクトルを計算し,そのベクトルと類似度の高い10語とその類似度を出力せよ.
positive,negativeを指定することで加算や減算が可能です。

コード

1
model.most_similar(positive=['Spain','Athens'], negative=['Madrid'],topn=10)

64. アナロジーデータでの実験

単語アナロジーの評価データをダウンロードし,vec(2列目の単語) - vec(1列目の単語) + vec(3列目の単語)を計算し,そのベクトルと類似度が最も高い単語と,その類似度を求めよ.求めた単語と類似度は,各事例の末尾に追記せよ.

コード

私の環境では処理に一時間程度かかりました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
with open('questions-words.txt') as f:
questions = f.readlines()
with open('64.txt','w') as f:
for i,question in enumerate(questions):
words = question.split()
if len(words)==4:
ans = model.most_similar(positive=[words[1],words[2]], negative=[words[0]],topn=1)[0]
words += [ans[0], str(ans[1])]
output = ' '.join(words)+'\n'
else:
output = question
f.write(output)
if (i%100==0):
print (i)

65. アナロジータスクでの正解率

64の実行結果を用い,意味的アナロジー(semantic analogy)と文法的アナロジー(syntactic analogy)の正解率を測定せよ.
先ほど出力したファイルを読み込み、適当なカラム同士を比較します。

コード

1
2
3
4
5
6
7
8
9
10
11
cnt = 0
ok = 0
with open('64.txt','r') as f:
questions = f.readlines()
for question in questions:
words = question.split()
if len(words)==6:
cnt += 1
if (words[3]==words[4]):
ok +=1
print (ok/cnt)

66. WordSimilarity-353での評価

The WordSimilarity-353 Test Collectionの評価データをダウンロードし,単語ベクトルにより計算される類似度のランキングと,人間の類似度判定のランキングの間のスピアマン相関係数を計算せよ.

コード

set1set2を結合したcombined.csvを利用すれば良いです。スピアマンの順位相関係数はpandasで計算できます。

1
2
3
4
5
6
7
8
import pandas as pd
df = pd.read_csv('wordsim353/combined.csv')
sim = []
for i in range(len(df)):
line = df.iloc[i]
sim.append(model.similarity(line['Word 1'],line['Word 2']))
df['w2v'] = sim
df[['Human (mean)', 'w2v']].corr(method='spearman')

67. k-meansクラスタリング

国名に関する単語ベクトルを抽出し,k-meansクラスタリングをクラスタ数k=5として実行せよ.

コード

国名のリストはこちらを利用しました。テキストファイルにコピペして、一部改行の修正をしました。

学習済みの語彙とは表記が一致していない国も多く、対応できるように置換を行いましたが、全ての国に対応している訳ではありません。

k-meansクラスタリングにはsklearnを利用しました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from sklearn.cluster import KMeans
with open('country.txt','r') as f:
lines = f.readlines()
countries = []
for line in lines:
country = line.split(' ')[-1].replace('\n','')
countries.append(country)
dic = {'United States of America':'United_States', 'Russian Federation':'Russia'}
ng = 0
vec = []
target_countries = []
for c in countries:
for k,v in dic.items():
c = c.replace(k,v)
c = c.replace(' ','_').replace('-','_').replace('_and_','_')
try:

vec.append(model[c])
target_countries.append(c)
except:
ng += 1
kmeans = KMeans(n_clusters=5, random_state=0)
kmeans.fit(vec)
for c,l in zip(target_countries, kmeans.labels_):
print (c,l)

68. Ward法によるクラスタリング

国名に関する単語ベクトルに対し,Ward法による階層型クラスタリングを実行せよ.さらに,クラスタリング結果をデンドログラムとして可視化せよ.

コード

デンドログラムを作成する際は、scipyを使うと良いでしょう。国名が多いので、文字が潰れないように工夫が必要です。

1
2
3
4
5
6
import matplotlib.pyplot as plt
from scipy.cluster.hierarchy import dendrogram, linkage
plt.figure(figsize=(32.0, 24.0))
link = linkage(vec, method='ward')
dendrogram(link, labels=target_countries,leaf_rotation=90,leaf_font_size=10)
plt.show()

69. t-SNEによる可視化

国名に関する単語ベクトルのベクトル空間をt-SNEで可視化せよ.

コード

t-snesklearnを使うと良いです。

1
2
3
4
5
6
7
from sklearn.manifold import TSNE
vec_embedded = TSNE(n_components=2).fit_transform(vec)
vec_embedded_t = list(zip(*vec_embedded)) # 転置
fig, ax = plt.subplots(figsize=(16, 12))
plt.scatter(*vec_embedded_t)
for i, c in enumerate(target_countries):
ax.annotate(c, (vec_embedded[i][0],vec_embedded[i][1]))

続きはまた明日!

最後に

全100問の解説に戻る

記事情報

  • 投稿日:2020年5月9日
  • 最終更新日:2020年5月9日