狐に騙され覚書

あぁこれ便利だなってことを忘れてもいいように覚書。主にプログラミング言語主体ですよ。

Jubatus で記事連動広告を表示したい話

はじめに

そういえば今更ですが昨年の10月に Jubatus Hackathon #1 に参加してきました。

Jubatus ハッカソン - connpass

発表時のスライドはこちらに綺麗にまとめていただいているので、ご参考にどうぞ。

Jubatus Blog: Jubatusハッカソンを開催しました

1日で企画〜実装まで持っていったとは言え、色々雑だったなぁと反省しています。 なので少し補足をしようと思います。

作ったもの

ハッカソンの少し前に、国内最大級の広告イベントに行ってきました。それに見事に感化されて、じゃあ広告系のやつを作ろう!と同チームの後輩に言ったらすんなりOKもらったので、それを作りました。

具体的な仕様や想定は以下の通り:

  • いわゆる owned media(記事)を持っていて、それにマッチする広告を表示したい
  • マッチするとは、記事の内容と広告の内容が類似することをいう
  • (仕事上がりで結構つらいのであまり頭を使いたくない)

特に重要なのは一番下の条件で、重みが非常に大きいです。

少し真面目に理由付けをすると、迷ったらできるだけシンプルな構成をとるという自戒があります。 なぜならば、複雑なシステムはメンテナンスコストが増大するからです。 特に機械学習を用いる場合、システムにバグ(や嬉しくない挙動)があったとして、

などなど、考慮しないといけないところが多いので、もうこれ以上仕事したくないからです(真面目)。 基本的にエンジニアは楽をするために自動化をするので、仕事が増えたら本末転倒なわけです(?)。

ちなみにコードはそのままだとたぶん動かないですが、github に上がってます。

chase0213/jubatus-hackathon-01 · GitHub

私たちのスライドはこちらです。

Jubatus hackathon 1_hiyoshi

システム構築

github をご覧になった方はお気づきと思いますが、当初は Rails + Elasticsearch + Jubatus の 3サーバ構成をとろうとしていました。 ただ、Elasticsearch の部分が本質的ではなかったので棄却されました。 使いたかった。。。

リクエストの流れは大体以下の通りです。

  • Railsサーバ上で owned media(記事)が掲載されている
  • 広告は json形式(タイトルと広告の概要文を含む)で、jubatus上で学習
  • ユーザーは適当な検索キーワードを入力して、記事を検索する
  • Railsサーバは絞り込んだ記事の内容を POST でバックエンドの Jubatus(python + Django で受ける)に送信する
  • リクエストを受け取った Jubatusサーバは、recommender を使用して、記事の内容に近い広告記事の id を Railsサーバに返却
  • Railsサーバは Jubatusサーバから受け取った id を元に広告を取得し、ユーザーに表示

つまり結局のところ、recommender に突っ込んでるだけです。

それから、記事と広告の類似度を判定するところは、mecab + ipadic を使って形態素解析したもの Jubatus のベクトルコンバータを使って特徴量として保持しています。

データ変換 — Jubatus

このコンバータが非常に優秀なので特徴量をこね回すところはほとんど何もしていません。 なのでノイズまみれになってあまり精度が出ないのですが、この件に関しては後述します。

デモ

AWS上にデプロイしてデモをしました。 ただそれなりのスペックのマシンを使ったので、今は(金銭上の理由で)止めてしまっています。 適当にコードをいじったらローカルでも動くので適当にいじってください。

構想

学習という学習の部分は、広告を動的に追加できるところで、あまり学習器の旨味を出せませんでした。 普通、機械学習って言えば使われる度に賢くなるというところを想像する方が多いと思いますので、その部分について簡単に意見を書いておきます(コードは書きません、悪しからず)。

まず、広告系で学習器を使うと言えば、実際にクリックされたものとそうでないものとでインプレッション率に差を付けるところだと思います。 つまり、良くクリックされる記事と広告の組み合わせに対しては、インプレッションを多めにして、そうでないものに対しては気まぐれにたまに表示する、ということです。

実際には作っていないのですが、classifier(分類器)を使ってできそうだと思っています。
具体的には、検索システムで絞りこまれた記事の内容と、クリックされた広告の内容の UNION をとって、クリックされたというラベル付きで classifier に突っ込んでおきます。 同様にして、クリックされなかったものに対しても記事と広告の UNION をクリックされなかったというラベルつきで保存しておくのですが、ここで 1点注意が必要です。

あるリンクがクリックされなかったとしても、ユーザーがそれに対して興味がないと判断するのは早計である。
なぜならば、多くの場合ユーザーは、他の多くの選択肢を提示されており、
そのリンクに対して興味がないことを能動的に示したわけではないからである。

なんか引用っぽくしましたが、私見です。 裏を返せば、クリックしたという情報はクリックしなかったという情報よりも強く扱われるべきです。

というわけで、この辺りを統計的にうまいことチューニングして classfier に突っ込んで 2値分類させれば、ユーザーがその組み合わせでクリックしそうかどうかを予測できます。 その値を上段(recommender)に返して、係数として上手く反映させると、たくさんクリックされる組み合わせはより多く表示されるようになります。

終わりに

最後の段落は机上の空論なので、落とし穴はそこら中に散らばっていると思います。 それから、上の方で「ノイズまみれ」と表現しましたが、これはある程度許容すべきです。 なぜならば、全くノイズの無い広告はユーザを退屈させるからです(広告は専門外なのであまり深く言及することは避けます)。