言語処理100本ノック-58:タプルの抽出

[言語処理100本ノック 2015](http://www.cl.ecei.tohoku.ac.jp/nlp100/)[「第6章: 英語テキストの処理」](http://www.cl.ecei.tohoku.ac.jp/nlp100/#ch6)の[58本目「タプルの抽出」](http://www.cl.ecei.tohoku.ac.jp/nlp100/#sec58)記録です。
前回ノックは全体の係り受け可視化でしたが、今回は特定の係り受けを抽出して出力です。8割くらいはやっていること同じです。

# 参考リンク

|リンク|備考|
|:--|:--|
|[058.タプルの抽出.ipynb](https://github.com/YoheiFukuhara/nlp100/blob/master/06.%E8%8B%B1%E8%AA%9E%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%81%AE%E5%87%A6%E7%90%86/058.%E3%82%BF%E3%83%97%E3%83%AB%E3%81%AE%E6%8A%BD%E5%87%BA.ipynb)|回答プログラムのGitHubリンク|
|[素人の言語処理100本ノック:58]()|多くのソース部分のコピペ元|
|[Stanford Core NLP公式](https://stanfordnlp.github.io/CoreNLP/)|最初に見ておくStanford Core NLPのページ|

# 環境

|種類|バージョン|内容|
|:--|:--|:--|
|OS|Ubuntu18.04.01 LTS|仮想で動かしています|
|pyenv|1.2.16|複数Python環境を使うことがあるのでpyenv使っています|
|Python|3.8.1|pyenv上でpython3.8.1を使っています<br>パッケージはvenvを使って管理しています|
|Stanford CoreNLP|3.9.2|インストールしたのが1年前で詳しく覚えていないです・・・<br>1年たってもそれが最新だったのでそのまま使いました|
|openJDK|1.8.0_242|他目的でインストールしていたJDKをそのまま使いました|

# [第6章: 英語テキストの処理](http://www.cl.ecei.tohoku.ac.jp/nlp100/#ch6)
## 学習内容
> Stanford Core NLPを用いた英語のテキスト処理を通じて，自然言語処理の様々な基盤技術を概観します．
>> [Stanford Core NLP](https://stanfordnlp.github.io/CoreNLP/), ステミング, 品詞タグ付け, 固有表現抽出, 共参照解析, 係り受け解析, 句構造解析, S式

## ノック内容
> 英語のテキスト（[nlp.txt](http://www.cl.ecei.tohoku.ac.jp/nlp100/data/nlp.txt)）に対して，以下の処理を実行せよ．

### [58. タプルの抽出](http://www.cl.ecei.tohoku.ac.jp/nlp100/#sec58)
> Stanford Core NLPの係り受け解析の結果（collapsed-dependencies）に基づき，「主語 述語 目的語」の組をタブ区切り形式で出力せよ．ただし，主語，述語，目的語の定義は以下を参考にせよ．

> - 述語: nsubj関係とdobj関係の子（dependant）を持つ単語
> - 主語: 述語からnsubj関係にある子（dependent）
> - 目的語: 述語からdobj関係にある子（dependent）

### 課題補足(「タプル」について)
「タプル」と聞くとPythonのTupleを想起してしまいましたが、今回はどうも違うようです。
まず、[Wikipedia「タプル」](https://ja.wikipedia.org/wiki/%E3%82%BF%E3%83%97%E3%83%AB)では以下のように書かれています。**「複数の構成要素からなる組」**のことです。

> タプルまたはチュープル（英: tuple）とは、複数の構成要素からなる組を総称する一般概念。

Stanford CoreNLPでは、[Stanford Open Information Extraction](https://nlp.stanford.edu/software/openie.html)の中でTupleについて触れています。

> Open information extraction (open IE) refers to the extraction of relation tuples, typically binary relations, from plain text, such as (Mark Zuckerberg; founded; Facebook).

そして、同じページにある以下の図が「タプル」についてわかりやすいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134273/6b94ee89-3bf3-2b0c-2d29-4e73c6776f49.png)


# 回答
## 回答プログラム [058.タプルの抽出.ipynb](https://github.com/YoheiFukuhara/nlp100/blob/master/06.%E8%8B%B1%E8%AA%9E%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%81%AE%E5%87%A6%E7%90%86/058.%E3%82%BF%E3%83%97%E3%83%AB%E3%81%AE%E6%8A%BD%E5%87%BA.ipynb)

```python
import xml.etree.ElementTree as ET

texts = []
# sentence列挙、1文ずつ処理
for sentence in ET.parse('./nlp.txt.xml').iterfind('./document/sentences/sentence'):

    output = {}
    
    # dependencies列挙
    for dep in sentence.iterfind('./dependencies[@type="collapsed-dependencies"]/dep'):

        # 関係チェック
        dep_type = dep.get('type')
        if dep_type == 'nsubj' or dep_type == 'dobj':

            # 述語の辞書に追加
            governor = dep.find('./governor')
            index = governor.get('idx')
            if index in output:
                texts = output[index]
            else:
                texts = [governor.text, '', '']

            # 主語 or目的語に追加(同じ述語なら後勝ち)
            if dep_type == 'nsubj':
                texts[1] = dep.find('./dependent').text
            else:
                texts[2] = dep.find('./dependent').text
            output[index] = texts

    for key, texts in output.items():
        if texts[1] != '' and texts[2] != '':
            print(sentence.get('id'), '\t', '\t'.join(texts))
```

## 回答解説
### XMLファイルのパス
以下のXMLファイルのパスと目的とする係り元、係り先のマッピングです。第5階層の`dependencies`タグは属性`type`が`collapsed-dependencies`のものを対象とします。
また、第6階層の属性`type`が`nsubj`か`dobj`のものが対象です。

|出力|第1階層|第2階層|第3階層|第4階層|第5階層|第6階層|第7階層|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|係り元|root|document|sentences|sentence|dependencies|dep|governor|
|係り先|root|document|sentences|sentence|dependencies|dep|dependent|

XMLファイルは[GitHub](https://github.com/YoheiFukuhara/nlp100/blob/master/06.%E8%8B%B1%E8%AA%9E%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%81%AE%E5%87%A6%E7%90%86/nlp.txt.xml)に置いています。

```xml:nlp.txt.xml(抜粋)
<root>
  <document>
    <docId>nlp.txt</docId>
    <sentences>
      <sentence id="1">

--中略--

        <dependencies type="collapsed-dependencies">
          <dep type="root">
            <governor idx="0">ROOT</governor>
            <dependent idx="18">field</dependent>
          </dep>

--中略--

          <dep type="nsubj">
            <governor idx="18">field</governor>
            <dependent idx="12">processing</dependent>
          </dep>

--中略--

          <dep type="dobj">
            <governor idx="13">enabling</governor>
            <dependent idx="14">computers</dependent>
          </dep>
```
### 出力用辞書作成
出力用の辞書型変数`output`を1文ごとに作成している箇所です。述語(`governor`)のインデックスを辞書のキーとして、辞書の値はリスト型にしていて中身は「述語テキスト」、「主語テキスト」、「目的語テキスト」を入れています。もし複数の主語、目的語を保つ場合は後勝ち方式にしています。

```python:
# dependencies列挙
for dep in sentence.iterfind('./dependencies[@type="collapsed-dependencies"]/dep'):

    # 関係チェック
    dep_type = dep.get('type')
    if dep_type == 'nsubj' or dep_type == 'dobj':

        # 述語の辞書に追加
        governor = dep.find('./governor')
        index = governor.get('idx')
        if index in output:
            texts = output[index]
        else:
            texts = [governor.text, '', '']

        # 主語 or目的語に追加(同じ述語なら後勝ち)
        if dep_type == 'nsubj':
            texts[1] = dep.find('./dependent').text
        else:
            texts[2] = dep.find('./dependent').text
        output[index] = texts
```

### 出力部
主語または、目的語があれば出力しています。

```python:
for key, texts in output.items():
    if texts[1] != '' and texts[2] != '':
        print(sentence.get('id'), '\t', '\t'.join(texts))
```

### 出力結果(実行結果)
プログラム実行すると以下の結果が出力されます。

```bash:出力結果
3 	 involve	understanding	generation
5 	 published	Turing	article
6 	 involved	experiment	translation
11 	 provided	ELIZA	interaction
12 	 exceeded	patient	base
12 	 provide	ELIZA	response
14 	 structured	which	information
19 	 discouraged	underpinnings	sort
19 	 underlies	that	approach
20 	 produced	Some	systems
21 	 make	which	decisions
23 	 contains	that	errors
34 	 involved	implementations	coding
38 	 take	algorithms	set
39 	 produced	Some	systems
40 	 make	which	decisions
41 	 have	models	advantage
41 	 express	they	certainty
42 	 have	Systems	advantages
43 	 make	procedures	use
44 	 make	that	decisions
```