LoginSignup
0
1

More than 3 years have passed since last update.

言語処理100本ノック-81(一括置換):複合語からなる国名への対処

Last updated at Posted at 2019-12-30

言語処理100本ノック 2015の81本目「複合語からなる国名への対処」の記録です。
今回も前回の「コーパスの整形」に引き続き前処理系で、主な処理は正規表現を使った文字置換です。ただ、国名リストを作る部分で手作業で面倒なことをしています。そのせいでプログラミング自体は難しくないのですが、時間がかかってしまいました。

参考リンク

リンク 備考
081.複合語からなる国名への対処.ipynb 回答プログラムのGitHubリンク
素人の言語処理100本ノック:81 言語処理100本ノックで常にお世話になっています
言語処理100本ノック 2015年版 (80~82) 第9章は参考にしました

環境

種類 バージョン 内容
OS Ubuntu18.04.01 LTS 仮想で動かしています
pyenv 1.2.15 複数Python環境を使うことがあるのでpyenv使っています
Python 3.6.9 pyenv上でpython3.6.9を使っています
3.7や3.8系を使っていないことに深い理由はありません
パッケージはvenvを使って管理しています

課題

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

今回は「1/100サンプリングのコーパスenwiki-20150112-400-r100-10576.txt.bz2を使っています。

81. 複合語からなる国名への対処

英語では,複数の語の連接が意味を成すことがある.例えば,アメリカ合衆国は"United States",イギリスは"United Kingdom"と表現されるが,"United"や"States","Kingdom"という単語だけでは,指し示している概念・実体が曖昧である.そこで,コーパス中に含まれる複合語を認識し,複合語を1語として扱うことで,複合語の意味を推定したい.しかしながら,複合語を正確に認定するのは大変むずかしいので,ここでは複合語からなる国名を認定したい.

インターネット上から国名リストを各自で入手し,80のコーパス中に出現する複合語の国名に関して,スペースをアンダーバーに置換せよ.例えば,"United States"は"United_States","Isle of Man"は"Isle_of_Man"になるはずである.

「インターネット上から国名リストを各自で入手し」が面倒です・・・

回答

国名リスト作成

1. 国名リスト取得

適当にググって「Country codes/names」なるページが良さそうと思ったのですが、問題文にある"Isle of Man"がありません。
"Isle of Man"はISO 3166-1にあるようなので、WikipediaのISO 3166-1からリストを取得しました。
つまり、以下の3つから国名リストを作成しています。

  1. 「Country codes/names」 Short name
  2. 「Country codes/names」 Official name
  3. 「Wikipedia ISO 3166-1」English short name

2. 先頭 the の除去

「Country codes/names」Official name列から取得した名前には先頭にtheがついているものがあり、後に邪魔なので除去しました。

3. 重複削除

3つから取得しているので国名が一部重複しており、重複削除しました。

4. 単一名削除

今回のお題は「複合語からなる国名」であり、単一語の国名は不要です。EXCEL上で=COUNTIF(A1,"* *")をして空白を挟んでいた国名を複合語と判断し、EXCEL関数結果が0の国名を除去しました。
※ノック96本目「国名に関するベクトルの抽出」で単一名も必要となるので、EXCELは残しておくと後が楽です。

5. マニュアル微調整

一部、そのまま使えないものがあり、マニュアルで微調整しました。手間がかかります・・・
下記が一例です。

変更後
Bolivia (Plurinational State of) Plurinational State of Bolivia
Cocos (Keeling) Islands Cocos Keeling Islands
Cocos Keeling
Cocos Islands
Keeling Islands

最終的に247個の国名ができました。

回答プログラム 081.複合語からなる国名への対処.ipynb

プログラムです。処理は短くたいしたことがありません(私はスキル不足で2から3時間ほどかけて作っていますが・・・)。
ただ、247個の国名の数だけ全文検索をして置換をするので、処理時間は約12分かかります。記事「言語処理100本ノック 2015年版 (80~82)」のようにsedコマンド使えばもっと速いのでしょうか?

import re

# ファイルから改行コードを除去し、ソートのために単語数を先頭に付加
with open('./081.countries.txt') as countires:
    country_num = [[len(country.split()), country.rstrip('\n')] for country in countires]

country_num.sort(reverse=True)

with open('./080.corpus.txt') as file_in:
    body = file_in.read()

for i, country in enumerate(country_num):
    print(i, country[1])
    regex = re.compile(country[1], re.IGNORECASE)
    body = regex.sub(country[1].replace(' ', '_'), body)

with open('./081.corpus.txt', mode='w') as file_out:
    file_out.write(body)

回答解説

国名一覧ファイルを読み込み、単語数をリストに付加して降順ソートしています。これは"United States of America"に対して先に単語数が少ない"United_States"を使って置換し、"United_States of America"としないためです。

# ファイルから改行コードを除去し、ソートのために単語数を先頭に付加
with open('./081.countries.txt') as countires:
    country_num = [[len(country.split()), country.rstrip('\n')] for country in countires]

country_num.sort(reverse=True)

正規表現ではre.INGNORECASEとすることで、大文字小文字を識別しないで置換対象にしています(この揺らぎが役に立つかは確認していないです)。

regex = re.compile(country[1], re.IGNORECASE)
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1