Edited at

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

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を用いよ.



82. 文脈の抽出


81で作成したコーパス中に出現するすべての単語tに関して,単語$ t $と文脈語$ c $のペアをタブ区切り形式ですべて書き出せ.ただし,文脈語の定義は次の通りとする.


  • ある単語$ t $の前後$ d $単語を文脈語$ c $として抽出する(ただし,文脈語に単語tそのものは含まない)

  • 単語$ t $を選ぶ度に,文脈幅$ d $は{1,2,3,4,5}の範囲でランダムに決める.



出来上がったコード:


main.py

# coding: utf-8

import random
fname_input = 'corpus81.txt'
fname_output = 'context.txt'

# 1行ずつ処理
with open(fname_input, 'rt') as data_file, \
open(fname_output, mode='wt') as out_file:
for i, line in enumerate(data_file):

# 1語ずつ処理
tokens = line.strip().split(' ')
for j in range(len(tokens)):

t = tokens[j] # 単語t
d = random.randint(1, 5) # 文脈幅d

# 前後d語以内の語の列挙
for k in range(max(j - d, 0), min(j + d + 1, len(tokens))):
if j != k:
print('{}\t{}'.format(t, tokens[k]), file=out_file)

# 経過表示
if i % 10000 == 0:
print('{} done.'.format(i))



実行結果:

結果ファイル「context.txt」の先頭部分です。


context.txtの先頭部分

Anarchism   is

Anarchism a
Anarchism political
Anarchism philosophy
is Anarchism
is a
is political
a is
a political
political Anarchism
political is
political a
political philosophy
political that
political advocates
philosophy is
philosophy a
philosophy political
philosophy that
philosophy advocates
philosophy stateless
that is
that a
that political
that philosophy
that advocates
that stateless
that societies
that often
(以下略)

全体はGitHubにアップしようかと思いましたが、約800MBになってしまったので断念しました。以降の問題もちょっとデータが大きいので、アップするのはやめておきます。


周辺の単語の抽出

問題80の「単語の何をベクトルにするのか」にも書いたように、単語をベクトルに変換する際はその周辺の単語の情報を使います。今回の問題はその準備作業になります。結果の1カラム目の単語をベクトル化する際に、2カラム目の単語の情報を使います。

実装自体は難しくないのですが、なぜ文脈幅を5で一定にせず毎回ランダムに揺らすのかは良くわかりませんでした。処理する情報量を減らすためかな...

 

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


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