読者です 読者をやめる 読者になる 読者になる

Jack of all trades

master of none. 多芸は無芸を地で行く、自作自演何でも屋。

Azure Machine Learning できるとこまでやってみよう Vol.4

↓同シリーズの過去記事

Azure Machine Learning できるとこまでやってみよう Vol.1 - Jack of all trades
Azure Machine Learning できるとこまでやってみよう Vol.1.5 - Jack of all trades
Azure Machine Learning できるとこまでやってみよう Vol.2 - Jack of all trades
Azure Machine Learning できるとこまでやってみよう Vol.3 - Jack of all trades

本エントリーはMicrosoft Azure Advent Calendar 2015の13日目です。

qiita.com

Vol.3からかなり期間が空いてしまい既に忘却の彼方ですが、Vol.4ではテキスト解析的なことをやってみます。

実現したいこと

適当なテキスト(ベタなところでTwitter上のツイートとか)にポジティブorネガティブのラベルを付加したデータを学習させて、入力したテキストに対してネガティブorポジティブを返すというフィルタ的なものを作成したいと思います。

実装

1. データの準備

任意のテキストに対して、その内容がネガティブかポジティブかを判定できるように学習させたいので、テキスト列(text)と評価列(value)を持ったCSVファイルを作成しました。
テキスト列についてはとりあえず評価しやすそうな文章をTwitterから拾ってきて、それらに手動で評価列をnegativeかpositiveで付加しています。
今回使用するモジュールの特性上(というかテキスト解析の場合ほぼそうなのですが)テキスト列には元の文章を分かち書きしたものが入っています。*1ちなみに分かち書きにはMeCabを使用しています。

f:id:sadynitro:20151212230225p:plain

準備したCSVファイルをこれまでの記事でやったのと同様、MLStudio上にアップロードしてDatasetとして保存します。

f:id:sadynitro:20151212230242p:plain

f:id:sadynitro:20151213113926p:plain

2. データの読み込み

まずは新しいExperimentを作成します。

f:id:sadynitro:20151212230312p:plain

Experimentの編集画面で「Saved Datasets」→「My Datasets」の中から、アップロードしたDatasetを選択、配置します。

f:id:sadynitro:20151213114005p:plain

f:id:sadynitro:20151212230328p:plain

3. Feature Hashing

Azure MLで使用可能な分類、予測等の学習アルゴリズムは基本的に説明変数として数値しか扱うことができません。 このままでは分かち書きしたテキストを説明変数、ネガポジの判定を目的変数にして学習させてもテキストが変な数値に置き換わって意味のない学習になるか 最悪エラーで学習が実行できないか、まぁそんなことになってしまいます。

そこでまずFeature Hashingというモジュールを使用して、分かち書きしたテキストをハッシュ化(ベクトル化)します。

Feature Hashingとは…については、先人たちのお知恵をWebの世界で探索していただければと思うのですが、ザックリいうと、その文書がどういった特徴で構成されているかを0 or 1の行列で表現するように変換する手法です。 例えば、テキストxに対してv[hoge]=0であればテキストxはhogeという特徴が含まれていない、逆にv[hoge]=1であれば含まれている、といった表現になります。

Feature Hashing - Wikipedia

Feature HashingモジュールはText Analyticsの中にあるので、これを選択・配置します。

f:id:sadynitro:20151213114048p:plain

f:id:sadynitro:20151212230353p:plain

適用する列はもちろんtextにします。

f:id:sadynitro:20151212230422p:plain

Feature Hashingのプロパティには対象列の選択以外に「Hashing bitsize」と「N-grams」を設定します。 Hashing bitsizeはハッシュ化後のベクトルの長さを設定します。N-gramsは平たく言うと文書中の文字をいくつまでまとめて判断するかという数値を設定します。 「私は田中一郎です」という文章を対象とした場合、N=2で設定すると

  • 私は
  • は田
  • 田中
  • 中一
  • 一郎
  • 郎で
  • です

という感じで文書を解析していきます。

全文検索 - Wikipedia

とりあえず今回は以下のような設定で実行してみます。本来はこのハッシュ化が学習に大きく影響するのでもっと真面目にチューニングすべきところかと思います。

f:id:sadynitro:20151212230449p:plain

ハッシュ化されてしまえば、textは不要なので、「Project Columns」モジュールで得られたハッシュ(ベクトル)とネガポジ判定(value)の列だけを選択します。

f:id:sadynitro:20151212230547p:plain

ハッシュ化して列を取捨選択した後のデータセットの中身を見てみるとこんな感じです。0ばかり並んでますが、ベクトルの後ろの方にはちゃんと幾つかの1が入ってます。

f:id:sadynitro:20151212230528p:plain

4. 学習モデルの構築

これで学習データの準備が整ったので、あとは毎度おなじみ「Split Data」でデータを学習用と評価用に分割して学習アルゴリズムと評価のモジュールを接続していくだけです。

f:id:sadynitro:20151212230609p:plain

今回は0.8で設定(全データ中80%を学習データ、20%を評価用データに振り分ける)

f:id:sadynitro:20151212230615p:plain

学習アルゴリズムとして「Two-Class Bayes point machine」を選択しました。2種類の分類フィルターといえばベイジアン…的な思い込みで選択しています。 これも本来はきちんと適用ケースに応じてアルゴリズムを選択、チューニングすべきところかと思います。

f:id:sadynitro:20151212230642p:plain

Labelにはもちろんvalueを選択。

f:id:sadynitro:20151212230711p:plain

「Two-Class Bayes point machine」モジュールのプロパティはこんな感じ。Iteration回数を変えるだけでも学習の結果が少し変わってくると思います。

f:id:sadynitro:20151212230716p:plain

5. 学習の実行

最後に評価のための「Score Model」モジュールを接続して、さらに評価結果を見やすくするために「Project Columns」モジュールで必要な列のみ取り出すようにします。

f:id:sadynitro:20151212230741p:plain

f:id:sadynitro:20151212230753p:plain

ここまで設定できたら、下のメニューにある「RUN」をクリックして学習を実行します。

f:id:sadynitro:20151213114146p:plain

6. 評価

学習の実行が完了したら、一番下に接続した「Project Column」モジュールの下○をクリックして、開いたメニューから「Visualize」を選択します。

f:id:sadynitro:20151213114157p:plain

「value」が実際の判定、「Scored Labels」が学習済みモデルが出力した判定です。

…精度が低い…正解率およそ70%…。

要は二択なので、適当に出力しても正解率は50%程度になるはず、と考えるともう少し精度が欲しいですね。

f:id:sadynitro:20151212230821p:plain

7. 改善のアイデア

学習の精度を上げるアイデアは幾つかあります。

ここまでに何度か言い訳のように「もう少し真面目に~」「もう少しきちんと~」と書いていた部分があるかと思いますが、そのあたりを改善するだけである程度効果があると考えています。 以下に改善すべきポイントを箇条書きします。

  • 学習データをクリーニングする。今回もできるだけネガティブ、ポジティブの感情がわかりやすいテキストをチョイスしているが、できるだけ特徴量が抽出しやすいデータを準備する。
  • 学習データの量を増やす。今回はたったの100件強のデータしか用意できなかった。本来テキストから特徴量を抽出してフィルタを作成しようと思うとデータが圧倒的に足りていない。*2
  • Azure ML上における「Feature Hashing」モジュールの特性をもう少しちゃんと理解してチューニングする。与えるテキストのエンコードやパラメータの設定によって学習に影響があると考えられる。
  • 学習アルゴリズムのパラメータを適切に設定する。これに関しては実際に実行してみながら、実験ベースでチューニングするしかないと思います。
  • 学習アルゴリズムとしてより適切なものを探す。各アルゴリズムに対して一般的に言われている「○○に強い」などの特徴を参考に、これも基本的には実験ベースで確認するしかないと思います。

まとめ

本記事では、Azure ML上でテキスト解析を行い、ネガポジ判定をする学習フィルタを構築する方法を説明しました。

因みに、学習の精度を上げるアイデアについても幾つか記述しましたが、それらを全部施したからといって思わしい精度まで向上する保証はありません。 さらにいうと、ここでの評価で精度が高かったからといって、全ての文書に対して同様の精度が得られるとも限りません。 さすがに厳密な精度を求められるシステムにおいては、綿密なチューニングともう少し複雑なモデルの構築が求められるでしょう。

しかしながら、上述のような簡単な操作で、お手軽にテキスト分類をしてくれる学習フィルタを構築できると考えると、やはりAzure ML恐るべしと言わざるを得ません。

ということで以上です。明日のMicrosoft Azure Advent Calendar 2015 14日目はtksarahさんです。よろしくどうぞ。

*1:なぜ分かち書きが必要かというと、日本語のように全ての単語が区切られることなくベタで書かれていて読み手がよしなに判断する言語というのは、まず形態素解析して分割(分かち書き)する必要があるわけです。逆に英語をはじめとするラテン言語等は全ての単語が必ずスペースによって区切られているため、この手間をかけることなくテキストの解析手法を適用することができます。

*2:様々な種類の文書に対してある程度の精度(汎用性)が欲しいという場合は特にデータの質と量が重要かと思います