suin.io

文章を放り込むだけ!Jubatusで作るブログの関連記事を推薦する人工知能

suin2016年8月22日

Jubatusはオンライン機械学習向け分散処理フレームワークで、学習データをリアルタイムに更新しながら分析処理を行うことができます。Jubatusでは、Classifier、Recommender、Anomaly、Regression、Graph、Statなど様々な分析ができるようですが、今回は関連するものを推薦してくれるAPIのRecommenderを使い、ブログの関連記事を提案する人工知能を作ってみたいと思います。

Jubatusはデータを突っ込むだけでできる人工知能

僕の感想ですが、機械学習と聞いたときは難しいデータサイエンスを熟知していないと扱えないかなと思っていました。しかし、Jubatusはデータを突っ込むだけである程度の人工知能を作れてしまいます。なので、僕のような機械学習ににわかなプログラマでもできてしまうわけです。この点はJubatusの大きな利点だと思います。

教師データの用意

Jubatus Recommenderの教師データを用意します。教師データはIDと値からなるものであれば良いようなので、投稿のURLをIDとして、本文からHTMLを取り除いたプレーンテキストを値として準備しました1。教師データはJSONで用意します:

training_data.json
{
    "http://qiita.com/suin/items/233e12462de68fcf302d": "Docker: MySQLのDBバックアップをDropboxに日次で保存する方法。suin/mysql-backup-dropboxは、...。",
    "http://qiita.com/suin/items/54ce152dd677d2dd6fd4": "docker-composeでPHP5.4〜PHP7.0まで単体テストする。次のようなYAMLを書いて、...",
    "http://qiita.com/suin/items/696051df872ba8bd379f": "「オブジェクトの特異クラスをオープンしてそこにメソッドを追加する構文」。class << object構文... ",
    "http://qiita.com/suin/items/e896332651fc1d600b6a": "dockerでmysqlコンテナを起動する。",
    ...
}

この教師データの完全版はGitHubにあります

Jubatusサーバのインストール(macOS)

macOSでのJubatusのインストールはHomebrewで簡単に行なえます。自然言語処理には形態素解析ツールのmecabも合わせて使うので、一緒にインストールします。

Jubatusのインストール:

brew tap jubatus/jubatus
brew install jubatus --enable-mecab

mecabと辞書のインストール:

brew install mecab mecab-ipadic

僕の環境ではjubatus 0.9.3がインストールされました:

$ jubarecommender --version
jubatus-0.9.3 (jubarecommender)

Jubatusサーバの設定

Jubatusサーバの設定はJSON形式です。今回は、mecabで形態素解析を行ない、記事中の名詞を抽出します。抽出した名詞の出現頻度をTF-IDFで計算するようにします。この趣旨のルールをJubatusの設定ファイルに表現すると次のようになります:

config.json
{
  "method": "inverted_index",
  "converter": {
    "string_filter_types": {},
    "string_filter_rules": [],
    "num_filter_types": {},
    "num_filter_rules": [],
    "string_types": {
      "mecab": {
        "method": "dynamic",
        "function": "create",
        "path": "/usr/local/lib/jubatus/plugin/libmecab_splitter.dylib",
        "arg": "-d /usr/local/lib/mecab/dic/ipadic",
        "base": "true",
        "include_features": "名詞,*"
      }
    },
    "string_rules": [
      {
        "key": "text",
        "type": "mecab",
        "sample_weight": "tf",
        "global_weight": "idf"
      }
    ],
    "num_types": {},
    "num_rules": []
  },
  "parameter": {}
}

Jubatusクライアントのインストール

JubatusのクライアントはPython、Ruby、Javaがありますが、ここではPython版を使います。インストールはpipコマンドでできます:

sudo pip install jubatus

教師スクリプトを作る

教師スクリプトをPythonで書きます。内容としては、先ほどの教師データtraining_data.jsonを読み込み、その内容をJubatusサーバに投げ込んでいくだけです。

train.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import jubatus
from jubatus.common import Datum
import json

JUBATUS_HOST = '127.0.0.1'
JUBATUS_PORT = 9199
JUBATUS_NAME = 'related-blog-posts'
TRAINING_DATA = './data/training_data.json'

# Jubatus推薦クライアントを生成
client = jubatus.Recommender(JUBATUS_HOST, JUBATUS_PORT, JUBATUS_NAME)

# 教師データファイルを読み込む
with open(TRAINING_DATA) as f:
    learning_data = json.load(f)
    for url, text in learning_data.items():
        # 教師データをJubatusに教え込む
        client.update_row(url, Datum({'text': text}))
        print url
    # 学習データをファイルに保存する(Jubatusの学習データはデフォルトでオンメモリ)
    client.save(JUBATUS_NAME)

上のPythonコードを見ると、数学や統計学の難しい数式は一切出てこないのがわかると思います。本当にテキストデータをつっこんでいるだけですが、これで機械学習が行えてしまいます。

Datum({'text': ...})'text'ですが、これはユーザが自由に付けられるキーです。blog_bodyなどにしても構いません。ここではconfig.jsonstring_rulesに出てくる"text"に対応させるため、'text' としています。

config.json
...
    "string_rules": [
      {
        "key": "text",
        "type": "mecab",
        "sample_weight": "tf",
        "global_weight": "idf"
      }
    ],
...

上で紹介した教師スクリプトは、バッチ的に教師データを流し込むものになっています。ブログを運用するときは、新しい記事が投稿されたら追加で学習したくなると思います。そのときは、記事ひとつひとつに対して、update_rowメソッドを呼び出すだけです。これだけで、学習データが更新されます。

client.update_row(new_blog_post_url, Datum({'text': new_blog_post_body}))

Jubatusサーバを起動して学習データを流し込む

学習するための手はずが整ったので、Jubatusにブログ記事を読んでもらい学習してもらおうと思います。まず、Jubatusサーバを起動します:

jubarecommender --listen_addr 0.0.0.0 --configpath config.json --datadir ./data

コンソールを別窓で開いて、学習データを流し込みます:

python train.py

これで学習は完了です。

Jubatusに関連記事を推薦してもらおう

学習データに基いて、Jubatusに関連記事を推薦してもらうにも、Jubatusクライアントを通じて行ないます。次のPythonスクリプトは、Jubatusに登録された記事IDから類似記事を推薦してもらう方法と、テキストを渡してそのテキストとの類似記事を推薦してもらう方法の2つをサンプルに書いてあります:

solve.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import jubatus
from jubatus.common import Datum
import json

JUBATUS_HOST = '127.0.0.1'
JUBATUS_PORT = 9199
JUBATUS_NAME = 'related-blog-posts'

# Jubatus推薦クライアントを生成
client = jubatus.Recommender(JUBATUS_HOST, JUBATUS_PORT, JUBATUS_NAME)

print "IDから関連投稿を推薦してもらう"
posts = client.similar_row_from_id('http://qiita.com/suin/items/fb58426e6c1eaa2b8e18', 5)
for post in posts:
    print post.id, post.score

print "テキストから関連投稿を推薦してもらう"
posts = client.similar_row_from_datum(Datum({'text': 'Dockerでコンテナを起動するには...'}), 5)
for post in posts:
    print post.id, post.score

それでは、Jubatusに関連記事を推薦してもらいましょう:

python solve.py

すると直ぐに次のように記事を推薦してくれます!:laughing:

IDから関連投稿を推薦してもらう
http://qiita.com/suin/items/fb58426e6c1eaa2b8e18 1.0
http://qiita.com/suin/items/36df6e80ce5aea389e59 0.436246454716
http://qiita.com/suin/items/c2ef8ff06b844be656cc 0.422848016024
http://qiita.com/suin/items/e896332651fc1d600b6a 0.396534264088
http://qiita.com/suin/items/00f0172438f7cffe935e 0.342201322317
テキストから関連投稿を推薦してもらう
http://qiita.com/suin/items/e896332651fc1d600b6a 0.377677410841
http://qiita.com/suin/items/7f6ffcf319acc172217b 0.264081209898
http://qiita.com/suin/items/36df6e80ce5aea389e59 0.199342146516
http://qiita.com/suin/items/fb58426e6c1eaa2b8e18 0.152336448431
http://qiita.com/suin/items/233e12462de68fcf302d 0.13839161396

まとめのようなもの

  • Jubatusならデータサイエンスに詳しくなくてもデータがあればそれなりに人工知能が作れる
  • Jubatus Recommenderならブログの関連記事を実現できる

ここで使った教師データや各種スクリプトがGitHubにてダウンロードできます。試してみたい方はどうぞご活用ください。suin/jubatus-examples


  1. Jubatus単体でもデータ変換の機能を使えばHTML文書からタグを取り除いてプレーンテキストにすることができます。今回の教師データに使うブログ記事にはコードブロックがあり、それを取り除いた地の文だけにしたかったので、<p>タグ<h1>タグなどのテキストを抽出した教師データを用意しました。 

RELATED POSTS