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


[言語処理100本ノック 2015](http://www.cl.ecei.tohoku.ac.jp/nlp100/)の挑戦記録です。環境はUbuntu 16.04 LTS ＋ Python 3.5.2 \:\: Anaconda 4.1.1 (64-bit)です。過去のノックの一覧は[こちら](http://qiita.com/segavvy/items/fb50ba8097d59475f760)からどうぞ。

## 第6章: 英語テキストの処理
>英語のテキスト（nlp.txt）に対して，以下の処理を実行せよ．

###56. 共参照解析
>Stanford Core NLPの共参照解析の結果に基づき，文中の参照表現（mention）を代表参照表現（representative mention）に置換せよ．ただし，置換するときは，「代表参照表現（参照表現）」のように，元の参照表現が分かるように配慮せよ．

####出来上がったコード：

```python:main.py
# coding: utf-8
import os
import subprocess
import xml.etree.ElementTree as ET

fname = 'nlp.txt'
fname_parsed = 'nlp.txt.xml'


def parse_nlp():
	'''nlp.txtをStanford Core NLPで解析しxmlファイルへ出力
	すでに結果ファイルが存在する場合は実行しない
	'''
	if not os.path.exists(fname_parsed):

		# StanfordCoreNLP実行、標準エラーはparse.outへ出力
		subprocess.run(
			'java -cp "/usr/local/lib/stanford-corenlp-full-2016-10-31/*"'
			' -Xmx2g'
			' edu.stanford.nlp.pipeline.StanfordCoreNLP'
			' -annotators tokenize,ssplit,pos,lemma,ner,parse,dcoref'
			' -file ' + fname + ' 2>parse.out',
			shell=True,		# shellで実行
			check=True		# エラーチェックあり
		)


# nlp.txtを解析
parse_nlp()

# 解析結果のxmlをパース
root = ET.parse(fname_parsed)


# coreferenceの列挙し、代表参照表現に置き換える場所情報の辞書を作成
# 	辞書は{(sentence id, 開始token id), (終了token id, 代表参照表現)}...
rep_dict = {}
for coreference in root.iterfind('./document/coreference/coreference'):

	# 代表参照表現の取得
	rep_text = coreference.findtext('./mention[@representative="true"]/text')

	# 代表参照表現以外のmention列挙、辞書に追加
	for mention in coreference.iterfind('./mention'):
		if mention.get('representative', 'false') == 'false':

			# 必要な情報の抽出
			sent_id = int(mention.findtext('sentence'))
			start = int(mention.findtext('start'))
			end = int(mention.findtext('end'))

			# すでに辞書にある（＝開始位置は同じだが終わりが違う）場合は先勝ち
			if not (sent_id, start) in rep_dict:
				rep_dict[(sent_id, start)] = (end, rep_text)


# 本文をrep_dictで置き換えながら表示
for sentence in root.iterfind('./document/sentences/sentence'):
	sent_id = int(sentence.get('id'))		# sentenceのid
	org_rest = 0							# 置換中のtoken数の残り

	# token列挙
	for token in sentence.iterfind('./tokens/token'):
		token_id = int(token.get('id'))		# tokenのid

		# 置換対象？
		if org_rest == 0 and (sent_id, token_id) in rep_dict:

			# 辞書から終了位置と代表参照表現を取り出し
			(end, rep_text) = rep_dict[(sent_id, token_id)]

			# 代表参照表現＋カッコを挿入
			print('[' + rep_text + '] (', end='')
			org_rest = end - token_id		# 置換中のtoken数の残り

		# token出力
		print(token.findtext('word'), end='')

		# 置換の終わりなら閉じカッコを挿入
		if org_rest > 0:
			org_rest -= 1
			if org_rest == 0:
				print(')', end='')

		print(' ', end='')

	print()		# sentence単位で改行
```

####実行結果：

```console:端末：先頭部分
Natural language processing From Wikipedia , the free encyclopedia Natural language processing -LRB- NLP -RRB- is [the free encyclopedia Natural language processing -LRB- NLP -RRB-] (a field of computer science) , artificial intelligence , and linguistics concerned with the interactions between computers and human -LRB- natural -RRB- languages . 
As such , NLP is related to the area of humani-computer interaction . 
Many challenges in NLP involve natural language understanding , that is , enabling [computers] (computers) to derive meaning from human or natural language input , and others involve natural language generation . 
History The history of NLP generally starts in the 1950s , although work can be found from earlier periods . 
In 1950 , Alan Turing published an article titled `` Computing Machinery and Intelligence '' which proposed what is now called the [Alan Turing] (Turing) test as a criterion of intelligence . 
The Georgetown experiment in 1954 involved fully automatic translation of more than sixty Russian sentences into English . 
The authors claimed that within three or five years , [a solved problem] (machine translation) would be a solved problem . 
However , real progress was much slower , and after the ALPAC report in 1966 , which found that ten year long research had failed to fulfill the expectations , funding for machine translation was dramatically reduced . 
Little further research in [a solved problem] (machine translation) was conducted until the late 1980s , when the first statistical machine translation systems were developed . 
Some notably successful NLP systems developed in the 1960s were SHRDLU , [SHRDLU] (a natural language system working in restricted `` blocks worlds '' with restricted vocabularies) , and ELIZA , a simulation of a Rogerian psychotherapist , written by Joseph Weizenbaum between 1964 to 1966 . 
Using almost no information about human thought or emotion , ELIZA sometimes provided a startlingly human-like interaction . 
When the `` patient '' exceeded the very small knowledge base , [ELIZA] (ELIZA) might provide a generic response , for example , responding to `` [the `` patient ''] (My) head hurts '' with `` Why do you say [My head] (your head) hurts ? '' 
. 
```

全体の結果は[GitHub](https://github.com/segavvy/nlp100_Python/tree/master/56)にアップしています。

###共参照とは
共参照（Coreference）とは、2つ以上の名詞が同一のものを指すことだそうで、「首相が初めて訪米した際、彼が歴史や文化に詳しいことを〜」みたいな文章があった場合に、「彼」＝「首相」と解析する処理が共参照解析だそうです。[Stanford Core NLPのサイトのAbout](http://stanfordnlp.github.io/CoreNLP/)の真ん中辺りにある「Coreference」に例が載っています。

Stanford Core NLPには、[Stanford Deterministic Coreference Resolution System](http://nlp.stanford.edu/software/dcoref.html)という共参照を解析する仕組みがあり、その解析結果がxmlファイルの`coreference`タグで出力されています。

```console:端末：nlp.txt.xmlの途中部分
    <coreference>
      <coreference>
        <mention representative="true">
          <sentence>1</sentence>
          <start>7</start>
          <end>16</end>
          <head>12</head>
          <text>the free encyclopedia Natural language processing -LRB- NLP -RRB-</text>
        </mention>
        <mention>
          <sentence>1</sentence>
          <start>17</start>
          <end>22</end>
          <head>18</head>
          <text>a field of computer science</text>
        </mention>
        <mention>
          <sentence>18</sentence>
          <start>23</start>
          <end>25</end>
          <head>24</head>
          <text>language processing</text>
        </mention>
        <mention>
          <sentence>19</sentence>
          <start>50</start>
          <end>52</end>
          <head>51</head>
          <text>language processing</text>
        </mention>
        <mention>
          <sentence>33</sentence>
          <start>15</start>
          <end>17</end>
          <head>16</head>
          <text>language processing</text>
        </mention>
      </coreference>
```

今回のコードは、このタグの解析がメインです。

`<coreference>`内には、代表参照表現を示す`<mention representative="true">`のデータがあるので、ここから代表参照表現を取得します。それ以外の`<mention>`は代表ではない参照表現なので、今回の問題における置換対象の位置情報になります。今回はこれらの情報を辞書`rep_dict`に詰め込みました。

あとは、[問題53](http://qiita.com/segavvy/items/ab6bb2b994aac061f51f)で対象にしていた`<sentence>`を列挙しながら`rep_dict`をチェックして、該当するものがあれば置換しながら出力しています。

###結果の表示
問題文では`代表参照表現（参照表現）`のように，元の参照表現が分かるように配慮せよとのことでしたが、この通りにしてみたところ代表参照表現の開始位置が分かりにくかったので、`[代表参照表現] (参照表現)`という形にしてみました。

ただ、英語が苦手なので、結果を見ても正しいのかどうかが実は良くわかりません^^;　代表参照表現と参照表現が一緒のものもパラパラ出てきてますが、これはちょっと変ですよね。もし私のコードが正しいのであれば、Stanford Core NLPの解析結果がおかしいのかも。共参照解析というのはかなり難しい処理なのかも知れませんね。

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

*実行結果には、[100本ノックで用いるコーパス・データ](http://www.cl.ecei.tohoku.ac.jp/nlp100/#data)で配布されているデータの一部が含まれます。この第6章で用いているデータのライセンスは[クリエイティブ・コモンズ 表示-継承 3.0 非移植](https://creativecommons.org/licenses/by-sa/3.0/legalcode)（[日本語訳](https://creativecommons.org/licenses/by-sa/3.0/deed.ja)）です。*