自然言語処理ライブラリGiNZAで固有表現抽出してみた

#この記事の目的

最近, Pythonで日本語での固有表現抽出(Named Entity Recognition; NER)を簡単に使いたいなと思っていろいろ探していたろころ, ```GiNZA```というものを知ったので使ってみました. 
ちなみに, 固有表現抽出は自然言語処理のタスクの１つで, 以下の図のように日付や人物など, 特定の単語を検出するもののことです. 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540956/4effe495-6bac-ac13-59c7-dea53d81874b.png)


# GiNZAについて

```GiNZA```は自然言語処理(Natural Language Processing; NLP)を行うためのライブラリの１つで, 固有表現抽出以外にも様々なタスクをこなすことができます. 
正確には, ```spaCy```という自然言語処理ライブラリがあるのですが, その日本語処理部分を担当しているといった感じです. そのため, ```spaCy```の使い方がわかる方なら早いと思います. 


詳細は, 以下をご確認ください. 今回は固有表現抽出に限って紹介します. 
GitHub：[megagonlabs/ginza](https://github.com/megagonlabs/ginza)
[第4回 spaCy/GiNZA を用いた自然言語処理](https://www.ogis-ri.co.jp/otc/hiroba/technical/similar-document-search/part4.html)


# 準備

はじめに, ```GiNZA```と```spaCy```を準備します. 

```python
!pip install -U ginza
```

```python
import spacy
from spacy import displacy
nlp = spacy.load('ja_ginza')
```

これで, ```spaCy```側で```GiNZA```のモデルが読み込めたので, 処理の準備完了です. 
```Jupyter Notebook```を使っている場合, ここでつまづくことがあるそうなので, その際は[GitHub](https://github.com/megagonlabs/ginza)をご参照ください. 

# データの用意

次に解析対象のサンプルデータを用意します. 
今回は, ロンウイット社が公開しているlivedoor ニュースのデータを使います. 
データは, 9つのジャンルに分かれたニュースなので, 今回はそれらから1つずつニューステキストを抽出し, 9つのニューステキストに対して, 固有表現抽出を行っていきます. 
これにより, テキストのジャンルの得意・不得意などが分かるのではないかという思惑です. 

ここからデータをダウンロードして解凍します. 
[livedoor ニュースコーパス](https://www.rondhuit.com/download.html)

```python
!wget https://www.rondhuit.com/download/ldcc-20140209.tar.gz
!tar zxvf ldcc-20140209.tar.gz
```

# 固有表現抽出
テキストファイルのパスを指定すれば, それを読み込んで解析を行うようにコードを書きました. 試しに, 独女通信の1記事を分析してみました. 

```python
#テキスト読み込み
filepath = "./text/dokujo-tsushin/dokujo-tsushin-4778030.txt"
with open(filepath) as f:
    s = f.read()

#ここでいろんな処理が行われる
doc = nlp(s) 

#固有表現抽出の結果の描画
displacy.render(doc, style="ent", jupyter=True)
```
結果はこんな感じです. 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540956/c94d302f-acf0-b217-7bf3-5cd3b2766439.png)

いい感じに抽出できていますね！
ただ, 見た目の問題ですが, 色の指定がPERSONやTIMEなどにしかされておらず, 少し見づらいです. そこでオプションで色を変えてみます. 

```python
#抽出したエンティティの種類に対して色を指定する
colors = {"COUNTRY":"#00cc00", "CITY":"#00cc00", "GPE_OTHER":"#00cc00","OCCASION_OTHER":"#00cc00",
          "LOCATION":"#00cc00", "LOCATION_OTHER":"#00cc00","DOMESTIC_REGION":"#00cc00","PROVINCE":"#00cc00",
          "STATION":"#00cc00", "CONTINENTAL_REGION":"#00cc00","THEATER":"#00cc00",

          "TIME":"#adff2f","DATE":"#adff2f","DAY_OF_WEEK":"#adff2f",
          "PERIOD_YEAR":"#adff2f", "PERIOD_MONTH":"#adff2f", "PERIOD_DAY":"#adff2f",

          "FLORA":"#adff99","FLORA_PART":"#adff99",
          "DISH":"#ffeb99","FOOD_OTHER":"#ffeb99",
          
          "AGE":"#3385ff","N_PERSON":"#3385ff","N_EVENT":"#3385ff","N_LOCATION_OTHER":"#3385ff","RANK":"#3385ff",
          "N_PRODUCT":"#3385ff","":"#3385ff","":"#3385ff","":"#3385ff","MEASUREMENT_OTHER":"#3385ff","PERCENT":"#3385ff",
          "N_ORGANIZATION":"#3385ff", "ORDINAL_NUMBER":"#3385ff", "N_FACILITY":"#3385ff","SPEED":"#3385ff",
          "PHONE_NUMBER":"#3385ff",

          "MONEY":"#ffff00",

          "COMPANY":"#99c2ff", "SCHOOL":"#99c2ff", "INTERNATIONAL_ORGANIZATION":"#99c2ff",
          "GOE_OTHER":"#99c2ff", "SHOW_ORGANIZATION":"#99c2ff","CORPORATION_OTHER":"#99c2ff",

          "CLOTHING":"#ff66a3",
          "PRODUCT_OTHER":"#ff66a3",

          "PERSON":"#c266ff",
          "POSITION_VOCATION":"#ebccff",

          "MUSIC":"#ff7f50", "MOVIE":"#ff7f50", "GAME":"#ff7f50", "SPORT":"#ff7f50", "BOOK":"#ff7f50", 
          "BROADCAST_PROGRAM":"#ff7f50", 
          
          "ANIMAL_DISEASE":"#cd5c5c"
          }

options = {"colors": colors}
displacy.render(doc, style="ent", options=options, jupyter=True)
```
場所系の単語は緑, 組織系の単語は青など, 適当に設定しました. 改善の余地大有りです. 
今回はあくまで実験なので, これで良しとして, これを使って9つのニュース記事を固有表現抽出しました. 結果は以下の通りです. 

#### 独女通信

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540956/36472dd8-dd40-0a9d-5c22-c8fe62b9c853.png)


#### ITライフハック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540956/040bbc86-c9a3-3180-0cc6-25ad97e70a51.png)


#### 家電チャンネル

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540956/1a380606-d6bb-e2b9-4b4e-58ccd58e0f5c.png)


#### livedoor HOMME

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540956/e8395bdf-53a7-024d-f879-9d6d42c76270.png)


#### MOVIE ENTER

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540956/303575dc-0918-7e29-ec62-83183e334ef4.png)


#### Peachy

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540956/cd1c74fa-3811-3c00-e4d9-11ddaf1bf7b4.png)


#### エスマックス

![im01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540956/a8d510e6-b176-901d-1e3b-d886b3fff1b3.png)


#### Sports Watch

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540956/a2658c31-df69-7f0f-0287-2533eaaf4338.png)

#### トピックニュース

![img01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540956/31f136b4-86f3-e7df-900a-529373c5b588.png)

色を設定すると, デフォルトよりは見やすくなりますね. (ちょっと目がチカチカする気もしますが...)
ニュースのジャンルによっても, エンタメ系は人物が多かったり, ガジェット系は製品や企業の名前が多かったりと一目瞭然ですね. 

肝心の精度ですが, ジャンルによっては多少気になる単語もあるものの, 概ねよく抽出できていると言えるのではないでしょうか. 

個人的にはITライフハックの記事で「ヤモリ」がFOODに分類されているのが気になってしまいました. 

# 参考

GitHub：[megagonlabs/ginza](https://github.com/megagonlabs/ginza)
オブジェクトの広場：[第4回 spaCy/GiNZA を用いた自然言語処理](https://www.ogis-ri.co.jp/otc/hiroba/technical/similar-document-search/part4.html)
株式会社ロンウイット：[livedoor ニュースコーパス](https://www.rondhuit.com/download.html)
spaCy：[Visualizing the entity recognizer](https://spacy.io/usage/visualizers#ent)
spaCy：[Named Entity Recognition](https://spacy.io/api/annotation#named-entities)