OpenNLPでMeCabのような英語の形態素解析

# 概要
日本語の形態素解析(MeCab)のようなことを英語でもやりたいのでApache OpenNLPを使用する

# 環境
OS: Windows7 64bit
言語: Java8
IDE: Eclipse4.6.1

# 目的
MeCabをコマンドラインで使用すると

>今日はいい天気ですね。
　　　　　　↓
　　　　　　↓
今日  「名詞,副詞可能,\*,\*,\*,\*,今日,キョウ,キョー」
は    「助詞,係助詞,\*,\*,\*,\*,は,ハ,ワ」
いい  「形容詞,自立,\*,\*,形容詞・イイ,基本形,いい,イイ,イイ」
天気  「名詞,一般,\*,\*,\*,\*,天気,テンキ,テンキ」
です  「助動詞,\*,\*,\*,特殊・デス,基本形,です,デス,デス」
ね    「助詞,終助詞,\*,\*,\*,\*,ね,ネ,ネ」
。    「記号,句点,\*,\*,\*,\*,。,。,。」

と形態素に分け、形態素の情報が表示される

※ipadic辞書を使用した場合、
「品詞、品詞細分類1、品詞細分類2、品詞細分類3、活用型、活用形、基本形、読み、発音」の情報が得られる

この情報から「形態素」「品詞」「基本形」の3つを取得して分析に用いたりする

同じことを英語で行いたいので、OpenNLPを利用して英語文から「形態素」「品詞」「基本形」を取得する


# 目次
1. OpenNLPが提供する機能
2. Javaの実装
  1. Javaの準備
  2. 分かち書き 
  3. 品詞分解
  4. 単語の原型化

# 1. OpenNLPが提供する機能
OpenNLP本体は多言語に対応している為、以下のような機能がある。

* Language Detector （言語判別器）
* Sentence Detector （文区切り器）
* Tokenizer （単語区切り器）
* Name Finder / Named Entity Recognition （固有表現抽出器）
* Part-of-Speech Tagger （単語に品詞を割り当てる）
* Lemmatizer （原型化）
* Parser （構文木を作る）
* Chunker （浅い構文木を作る）
* Document Categorizer （文書分類器）
* Coreference Resolution （指示語の参照先を見つける）

「形態素」「品詞」「基本形」を取得したい為、今回は

* Tokenizer （単語区切り器）
* Part-of-Speech Tagger （単語に品詞を割り当てる）
* Lemmatizer （原型化）

を扱う

# 2. Javaの実装

## 1. 準備
mavenプロジェクトを作成し、pom.xmlに以下を追加

```
<dependency>
  <groupId>org.apache.opennlp</groupId>
  <artifactId>opennlp-tools</artifactId>
  <version>1.8.4</version>
</dependency>
```

また、以下のファイルをOpenNLPのサイトからダウンロードしてプロジェクト内に置き、パスが通るようにする

* en-token.bin
    * Tokenizerに利用するバイナリファイル
    * ダウンロード先
http://opennlp.sourceforge.net/models-1.5/

* en-pos-maxent.bin(en-pos-perceptron.bin)
    * Part-of-Speech Taggerに利用するバイナリファイル
    * ダウンロード先
http://opennlp.sourceforge.net/models-1.5/


* en-lemmatizer.txt
    * Lemmatizerで利用する単語の原形辞書
    * ダウンロード先
https://raw.githubusercontent.com/richardwilly98/elasticsearch-opennlp-auto-tagging/master/src/main/resources/models/en-lemmatizer.dict

※ en-lemmatizer.txtはリンク先のデータをテキストデータにして利用している

## 2. 分かち書き

```
// Tokenizerの設定
InputStream modelIn = new FileInputStream("~/en-token.bin");
TokenizerModel model = new TokenizerModel(modelIn);
Tokenizer tokenizer = new TokenizerME(model);

message = "It is a fine day today.";
String[] morphemes = tokenizer.tokenize(message);

System.out.println(Arrays.asList(morphemes));
>> [It, is, a, fine, day, today, .]

```

## 3. 品詞分解

```
// Part-of-speech Taggerの設定
InputStream posModelIn = new FileInputStream("~/en-pos-maxent.bin");
POSModel posModel = new POSModel(posModelIn);
POSTaggerME posTagger = new POSTaggerME(posModel);

// 分かち書きしたデータを用いる
String [] tags = posTagger.tag(morphemes);
System.out.println(Arrays.asList(tags));
>> [PRP, VBZ, DT, JJ, NN, NN, .]
```

※OpenNLPの品詞情報は以下のサイトを参照
http://dpdearing.com/posts/2011/12/opennlp-part-of-speech-pos-tags-penn-english-treebank/


## 4. 単語の原形化

```
// Lemmatizerの設定
InputStream dictLemmatizer = new FileInputStream("~/en-lemmatizer.txt");
DictionaryLemmatizer lemmatizer = new DictionaryLemmatizer(dictLemmatizer);

// 分かち書きしたデータ、品詞データを用いる
String [] lemmas = lemmatizer.lemmatize(morphemes, tags);
System.out.println(Arrays.asList(lemmas));
>> [it, be, a, fine, day, today, O]
```

※ 単語の原形化の結果に表れる「O」は品詞情報が上手くとれなかったり、固有名詞だったりして原形化ができない場合に表示される


思っていた以上に単語の原形化の結果が「O」になることが多いので、形態素のデータに置き換える等の調整が必要。


# 参考リンク
* [Apache OpenNLP Developer Documentation](https://opennlp.apache.org/docs/1.8.1/manual/opennlp.html)
* [Apache OpenNLPに関する調査](https://gist.github.com/miyakawataku/05563a8a13b39c432d9beba1e3af75d0)
* https://www.tutorialkart.com/opennlp/lemmatizer-example-in-apache-opennlp/