Elasticsearch with Amazon Machine Learning

Kunihiko Kido
Hello! Elasticsearch.
12 min readAug 28, 2015

--

ElasticsearchとAmazon MLを使って文章ベースで自動カテゴライズするための機械学習モデルを作る

Elasticsearchには色々なAPIが用意されているので、それらのAPIを色々使って今回やろうとしていることに近いこともできるのですが、今回は機械学習に Amazon Machine Learning 使ってみようかと。

やりたいことは、各ドキュメントの文章を元に、3つ以上の分類を予測するための機械学習モデルの作成です。いわゆる多項分類(Multiclass Classification)。

Elasticsearchはこのモデルを作成するための、教師データ作成に使います。Elasticsearchを使うことで、言語処理などの正規化をElasticsearchに任せてしまうことができるというメリットがあります。

正解データの作成

正解データの作成は、Elasticsearchに文章とカテゴリが付与されたデータをインデックスするだけです。既に商品データなど、インデックスされていればそれを使っても良いです。

今回は良い評価結果が出そうなニュース記事を使用しました。ジャンルは「経済」「エンタメ」「IT・科学」の3ジャンルです。

ドキュメンの内容はこんな感じ

{
"title": "原油安の「マイナス面」無視できず…"
"contents": "原油相場の下落が続いている。21日のニューヨーク市場で原油先物相場は国際指標の米国産標準油種(WTI)が …"
"category": "経済"
}

"contenst" 属性の内容をもとに "category" 属性のカテゴリに分類するための機械学習モデルを作成します。

評価対象の単語の選定

多分この単語の選定が一番の肝です。Amazon Machine Learning の教師データは評価項目を固定にする必要があるので、文章ベースの教師データを作成する際には、共通の評価対象の単語を選定する必要があると考え、事前にその単語を選定することにしました。

重要!:各カテゴリごとに重要(特徴的な)な単語を同じ数だけ選定する

Significant Terms Aggregation を使って自動抽出

評価対象の単語を人力で選定するのは大変なので、Elasticsearch の Significant Terms Aggregation を使用します。この Aggregation は、ある文章の集合から、重要な単語を集計してランキングしてくれます。単に出現回数が多い順とかではないので、文章全体で共通で使われているような単語はスコアは低くなります。

参考:https://speakerdeck.com/elasticsearch/the-significant-terms-aggregation

今回は以下のクエリで、記事の内容("contents"フィールドの文章)を対象にカテゴリごとに重要な単語50単語、合計150単語を抽出しました。

{
"query": {"match_all": {}},
"aggs": {
"categories": {
"terms": {"field": "category"},
"aggs": {
"significantTerms": {
"significant_terms": {"field": "contents", "size": 50}
}
}
}
}
}

抽出された単語は各カテゴリごとに、

「経済」:市場、株式、中国、経済、金融、景気、株価、...
「IT・科学」:画像、pc、watch、ユーザー、windows、製品、...
「エンタメ」:女優、俳優、番組、ドラマ、日本テレビ、テレビ、...

気持ち悪いぐらいそれっぽい単語が抽出できていますw

教師データの作成

あとは、Elasticsearchにインデックスされているデータを抽出して、各ドキュメントごとに評価対象単語の出現頻度をプロットしたデータを作成します。

最終的には以下のようなCSVファイルを作成します。今回は約1000ドキュメントを対象にデータを作成しました。

DocumentId,Category,Term001,Term002,Term003,...
1,経済,2,1,5,3,0,1,2,4,4,1,2,0,0,0,1,0,1,0,1,1...
2,経済,6,1,23,16,1,10,0,0,0,3,1,0,0,1,0,0,1,8,0...
...

※ ヘッダーには日本語が使えないので、英数字にしてます。

Elasticsearchから各種ドキュメントの単語の出現頻度の情報は、Term VectorsMulti Term Vectors APIを使うと取得できるので、以下のような流れでAPIを使用して取得します。

  1. Scan and Scroll でドキュメント群を抽出
  2. Multi Term Vectors APIでドキュメントごとの単語出現頻度を取得
  3. 評価対象単語を対象にCSVに書き出す。※出現しない単語は0固定

Term Vectors API で取得できる情報は、TF-IDFなどを計算するための情報も取得できるのですが、予測はあくまでも Amazon ML を使用するので、単語の出現頻度(Term Frequency)の値をそのまま使用しました。

機械学習モデルの作成

この辺りの手順は色々なブログで紹介されているので、ここでは簡単な流れと注意点だけ紹介します。

  1. 作成したCSVをAmazon S3へアップロード
  2. Amazon Machine Learning でデータソースの作成
  3. Amazon Machine Learning でモデルの作成(多項分類)
  4. Amazon Machine Learning でモデルの評価

まず、Amazon S3へアップロードする前に作成したデータの内容をランダムにソートしてください。Amazon MLはデータソースの7割を教師データで使用し、3割を評価データとして使用するため、データの内容が偏っていると評価結果が下がる可能性があります。できるだけカテゴリごとに均等なデータを作成した方が良いです。

Amazon Machine Learning はウィザード形式でデータソースの作成から、モデルの作成、評価の実施まで自動で行ってくれるので、比較的操作はわかりやすいです。

評価結果

今回作成したモデルは、平均9割の確率で分類できるモデルが作成できました。出来過ぎですね。

「Explore model performance」をクリックするとより詳細な結果を見ることがきます。

おそらく、対象のドキュメントがある程度の長さの文章量と内容がちゃんとしていること、分類数が3つと少ないこと、あとは、Elasticsearch の Significant Terms Aggregation の重要語を集計する機能が優れていることが良い結果につながっているのかと思われます。

あまり良いモデルが作れなければ、ElasticsearchのAnalyzerの処理を見直してみるとか、数値化可能な多の属性を追加してみるとか、試行錯誤してチューニングしてみてください。

今回試してみて、重要なポイントは

  • 教師データは各カテゴリごとに均等に用意する
  • 評価対象単語も各カテゴリごとに均等に用意する
  • TF-IDFの計算は事前にしなくても大丈夫
  • 教師データはランダムにしておく
  • Significant Terms Aggregation ってすごい!

といったところでしょうか、今後は分類数を多くしてみたり、他のコンテンツや、もう少し曖昧な分類、例えば問い合わせの対応優先度とかで、精度がどれくらい変わるのか試してみたいと思います。

さいごに

今回紹介したElasticsearchから教師データを作成する手順をAtomエディタのプラグインにしました。これを使うとElasticsearchから、評価対象単語の抽出と、CSVデータ作成まで、各種コマンドを実行するだけでできるので、興味のある方はチャレンジしてみてください。

追記:TEXTフィールドを使う

これまで説明した内容は、文章を数値化して機械学習モデルの作成のインプットに使用しましたが、ここではテキストをインプットデータに使用してみます。

Amazon Machine Learning は以下の4つのフィールドタイプが定義できます。

  • NUMERIC
  • CATEGORICAL
  • TEXT
  • BINARY

TEXTフィールドについては、デフォルトでスペース区切りの個々の単語とターゲットフィールドの相関を計算するようなので(参考:http://docs.aws.amazon.com/ja_jp/machine-learning/latest/dg/data-transformations-reference.html)、今回使用したデータを使用して以下のようなデータフォーマットも試してみました。

DocumentId,category,contents
1,経済,しまむら アメリカ ウィーゼンタール カナダ カード ...
2,エンタメ,akb nhk nmb pr さや てん ば みなみ ゆり アイドル ...
4,IT・科学,ジアゼパム データベース ベンゾ ベンゾジアゼピン 内訳 ...
5,経済,pr エレベーター コンパクト シティー トラフ バス バスターミナル ...

Elasticsearchで言語処理済み(形態素解析、特定品詞の除外など)”contents”属性の内容を半角スペース区切りでつなげてそのままcontentsフィールドのテキストデータとして使用します。(fielddata_fields パラメータを指定してフィールドのアナライズ済みのデータを取得)

{
"query": {"match_all": {}},
"fielddata_fields": ["contents"]
}

この方法だと、あらかじめ評価対象の単語を選定する必要もないので、比較的簡単にデータを作成することができますね。

この結果はと言うと、数値化した例と同じく約9割と優秀なモデルが作成できました。

TEXTフィールドはデフォルトではスペース区切りの個々の1単語(default to n-gram transformation with window size=1)をインプットで使用しますが、この数値の調整もできるようなので、Amazon ML側での精度の調整もできそうです。

TEXTフィールドを使う場合、日本語は分かち書きしない言語なので、インプットのデータとして文章をそのまま使用すると使い物にならないモデルが作成されてしまいますが、言語処理したデータであれば精度を上げやすいようです。

非定型なテキストデータをもとに優れた機械学習モデルを作成するには、日本語の場合は言語処理が必ず必要そうなので、数値化するにしろ、テキストデータを使用するにしろ、Elasticsearchとの相性は良いような気がします。数値化した文章をインプットする例の方は、単に Significant Terms Aggregation の精度の検証になってしまっているような気もしますが。。。

追記:分類数を増やしてみた

文章だけで多項分類の機械学習モデル作成して、分類数増やした場合の精度も気になるところです。

今回は、TEXTフィールドを使う方法で、3分類から19分類に増やしてみたのですが、コンテンツの内容が良いのか、そこそ良い結果になりました。精度が若干落ちているのは、分類ごとのデータ数も少ないせいなのかな?トピックがはっきりしていない「xxx総合」と言うカテゴリは若干精度が落ちますね。

記事の内容だけで19分類した結果はこちら

記事の内容のみで教師データ作成

さらに同じデータを使って記事の内容に加え、記事のタイトルも教師データに含めてみました。タイトルデータも記事の内容と同じくElasticsearchでアナライズ後の単語を使ってます。

記事の内容+記事のタイトルで19分類した結果はこちら

記事のタイトル+内容で教師データ作成

精度が78%から90%に上がってますね!精度を上げたい場合は属性を増やすことも有効な手段のようです。

--

--