Amazon Machine Learning のデータソースで日本語テキストを扱う方法

Amazon Machine Learning (Amazon ML)で日本語のテキストデータを使うと精度が上がらないという記事を見かけたので、本当かどうか検証してみました。
※筆者は機械学習に明るいわけではなので、詳しい方が読んで誤りに気づかれた場合は是非ご指摘ください。

##はじめに結論
Amazon MLに日本語のテキストを**そのまま入れる**と確かに精度が上がりにくいと思われます。
これは、Amazon MLが日本語テキストを分かち書きせず一塊のままインプットデータとして扱ってしまうためです。
Amazon MLはTEXTフィールドに対して空白区切りの単語uni-gramで変換を行い、モデルのインプットデータに使用します。
日本語のテキストを使用する場合は、**事前に分かち書きをした上で**データソースとしてアップロードすると、精度が出やすいと考えられます。

##検証内容
###テストデータ
テストには以下のBlogで紹介されている企業名辞書データを使用させて頂きました。
http://yut.hatenablog.com/entry/20130210/1360456363

データはgithub上で公開されています。
https://github.com/yutakikuchi/Data/blob/master/corps.txt

データには証券コード、上場市場、企業名、説明文が含まれています。
このデータを使って、**「企業の説明文からその企業が業種分類[機械]に該当するかを推定する」**というタスクを想定します。
元データは業種ごとにデータが並べてあるので、各データに対して「業種分類[機械]かどうか」を示すフィールド(isMachineIndustryフィールド)を追加して使用します。
割合としては**機械業が231件**に対し、**非機械業が3292件**となりました。

データソースのスキーマは以下のようになります。
* id(NUMERIC)
* market(CATEGORICAL)
* corporateName(TEXT)
* description(TEXT)
* isMachineIndustry(BINARY)





###分かち書きせずにモデルを作った結果
まずdescriptionフィールドを分かち書きせず、そのままモデルのインプットデータにしてみます。
データサンプルとしては下記のような形。

```corps.csv
id,market,corporateName,description,isMachineIndustry
5703,東証1部,日本軽金属ホールディングス(株),国内唯一の製錬工場持つアルミ一貫メーカー。化成品・地金と川下展開も。１２年１０月持株会社化,0
6382,東証2部,トリニティ工業(株),トヨタグループ向けが８割超。塗装設備首位。設計からプラントまで一貫化。自動車部品も,1
```

AUCの結果は下記のようになり、モデルとしては全く使い物にならないという警告が表示されました。

![SnapCrab_NoName_2015-7-5_21-38-35_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/51577/6febd904-f1e4-71e9-9324-bf4c78fa147d.png)

###分かち書きしてモデルを作った結果

次に description フィールドを mecab + IPA dic で分かち書きしたデータをインプットデータにしてみます。

```corps-wakati.csv
id,market,corporateName,description,isMachineIndustry
5703,東証1部,日本軽金属ホールディングス(株),国内 唯一 の 製 錬 工場 持つ アルミ 一貫 メーカー 。 化成 品 ・ 地金 と 川下 展開 も 。 １ ２ 年 １０月 持株 会社 化 ,0
6382,東証2部,トリニティ工業(株),トヨタ グループ 向け が ８ 割 超 。 塗装 設備 首位 。 設計 から プラント まで 一貫 化 。 自動車 部品 も ,1
```

AUCの結果は下記のようになり、モデルとしても優秀であるとコメントが表示されました。

![SnapCrab_NoName_2015-7-5_21-42-5_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/51577/3c685f97-17bd-9408-7994-ae764abae1ae.png)

###実際にBatch Predectionしてみた
分かち書き後のデータを3000件/523件に分けて3000件の方でモデルを作り直し、残りの523 件に対して Batch Predition させてみました。
判定結果としては正しく予測できたのが523件中492件。
結果としては悪くないのではないかと思います。

##そもそもTEXTフィールドはどう扱われるのか
Amazon MLではデータソースのスキーマで4つのフィールドタイプを定義できます。

* NUMERIC
* CATEGORICAL
* TEXT
* BINARY

このうち、日本語のテキストデータは基本的にTEXTフィールドで処理をすることになります。
Amazon MLのインプットデータとして使用するCSVでは[Unicodeのプレーンテキストデータを扱える](http://docs.aws.amazon.com/machine-learning/latest/dg/creating_datasources.html#csv-format-requirements)ので、日本語の文字列が含まれること自体は問題ありません。

>* Plain text using a character set such as ASCII, Unicode, or EBCDIC.

しかし、TEXTフィールドについてはドキュメントの[Transformationのセクション](http://docs.aws.amazon.com/machine-learning/latest/dg/transforming_data.html#data-transformations-reference)に以下の記述があります。

>N-grams with size 1 are generated implicitly for all inputs whose type is marked as text in the data schema, so you do not have to ask for them. Finally, keep in mind that n-grams are generated by breaking the input data on whitespace characters. 

これを読む限り、TEXTフィールドはデフォルトでスペース区切りのn-gram(Size=1)のTransformationを適用した状態でトレーニングのインプットになるようです。
つまり、スペース区切りの無い日本語のテキストでは単語ごとの区切りは自動ではつかず、**一塊のデータとして扱われてしまう**ということです。

データを分かち書きした上でAmazon MLに投入すると、テキスト中のスペースで区切られた個々の単語とターゲットフィールドの相関を計算します。
これにより、日本語のテキスト全体をそのままインプットとして処理する場合に比べ、精度を上げやすくなります。

##その他注意事項など
* もちろん日本語データを分かち書きすればなんでも精度が上がるわけではありません。もともとのデータについては想定するタスクに適したものを準備する必要があります。

* データソースを作成した後、モデルのトレーニングと評価用にデータを分けますが、Amazon MLは指定した割合に従って**頭から順に**データを分割してしまいます。
トレーニング用・評価用に均等に分散するために、データはあらかじめランダムに並び替えた上でデータソースを作りましょう。

* Amazon MLの使い方は一度[チュートリアル](http://docs.aws.amazon.com/machine-learning/latest/dg/tutorial.html)をやると把握しやすいです。