30分でわかるレコメンデーションエンジンの作り方

レコメンデーションというのはamazonとかで見かける「XXXを買った人はYYYも買っていますよ」というサービスのこと。最近ではレコメンデーションは珍しいものではなく多くのサービスで導入されている。
またレコメンデーションを実現するレコメンデーションエンジンを開発している企業もわりと多くて検索すると結構たくさん出てくる。

「レコメンデーションエンジン」でぐぐった結果

そんなレコメンデーションエンジンだが作るのはそれほど大変ではない。というか情報検索の基礎知識があれば誰でも作れる。ので作り方の解説をしてみるよ。


レコメンデーションは何を与えると何が返ってくるの?
まずはレコメンデーションの入出力の話。入力としては「ユーザ」もしくは「アイテム」というものが考えられる。「ユーザ」というのはレコメンデーションを利用しているユーザのこと。「アイテム」というのはレコメンデーションの対象となるもので例えばamazonなら本やCD、DVDなど。出力は当然、レコメンデーションの対象である「アイテム」となる。
では入力が「ユーザ」と「アイテム」ではどういう違いがあるか?入力が「ユーザ」ならユーザ自身に対して推薦を行う。amazonのトップページにアクセスしたときに出てくる「これにも注目」や「New for You」の項目などがそれに当たる。このような「ユーザ」に対して「アイテム」を推薦する方式をユーザベース・レコメンデーションという。
また入力が「アイテム」ならレコメンデーションの対象となるもの同士で似ているものを推薦する。amazonで個別の商品ページを閲覧しているときに「この商品を買った人はこんな商品も買っています」という項目に出てくるものなどがそれに当たる。このような「アイテム」に対して「アイテム」を推薦する方式をアイテムベース・レコメンデーションという。
より詳細な解説は神嶌先生(@shima__shimaさん)の資料(http://www.kamishima.net/jp/research.html)が詳しいので一読すると良い。


レコメンデーションのしくみはどうなってるの?
レコメンデーションというと大変高度で仰々しい印象があるが、実際は入力データ同士の類似度を計算しているだけ。ユーザベースのレコメンデーションなら「自分」(推薦の対象となるユーザ)と類似度の高い別の「ユーザ」を見つけてきて、その「ユーザ」が過去に閲覧した(購入した)「アイテム」でまだ「自分」が持っていない「アイテム」を推薦すれば良い。アイテムベースのレコメンデーションなら現在閲覧しているページの「アイテム」と類似度の高い「アイテム」を推薦すれば良い。類似度としてはcosine距離やdice係数など多くの尺度があるので好きなものを選択すれば良い。
類似度を計算するには「ユーザ」なり「アイテム」なりの「データ」をベクトルとして表すのが一般的。例えばユーザAのベクトルとしてユーザAが閲覧(購入)した「アイテム」を列挙して{本1,CD1,DVD1}とする。同様にユーザBのベクトルを{本1,CD1,DVD2}とするとユーザAとユーザBで共通している「アイテム」は{本1,CD1}の2つなので類似度2、というような計算ができる。「アイテム」同士の類似度を計算する場合は「ユーザ」と「アイテム」をひっくり返して考えれば良い。このように「ユーザ」が閲覧(購入)した「アイテム」の情報を用いた類似度計算をする推薦方式を協調フィルタリングという。
もしレコメンデーションを導入したいサービスが立ち上げ直後で閲覧(購入)情報がほとんど(あるいはまったく)ない場合はどうするか?この場合「ユーザ」や「アイテム」に固有の情報を使う。例えば「ユーザ」がアカウントを作成したときに興味あるジャンルなどを登録してもらって、そのジャンルの人気商品を「購入した」ことにしてしまう。また「アイテム」の商品解説文に似たようなことが書いてある2つの「アイテム」があったら、それらをどちらも購入した「架空のユーザ」を用意する、などが考えられる。こうした「ユーザ」や「アイテム」に固有の情報を利用した推薦をコンテンツベース・レコメンデーションあるいはコンテンツマッチという。
教科書としては徳永先生の「情報検索と言語処理」はデータ間の類似度計算方法についてわかりやすい説明があるのでこの本を読めばとりあえずレコメンデーションエンジンを作ることができる。また機械学習によって類似した「ユーザ」や「アイテム」を見つけても良い。


ここでちょっと頭の整理を・・・
ここでこれまでの内容を整理。レコメンデーションは「ユーザ」に対して「アイテム」を推薦する「ユーザベース」、「アイテム」に対して「アイテム」を推薦する「アイテムベース」があった。またレコメンデーションの招待は単純な類似度計算で、その類似度計算に閲覧(購入)情報を使う「協調フィルタリング」、「ユーザ」や「アイテム」に固有の情報を使う「コンテンツマッチ」があった。


ユーザベースVSアイテムベース
レコメンデーションの方式として「ユーザベース」と「アイテムベース」どちらが良いのかを考えてみる。
「ユーザベース」の推薦では「ユーザ」に対して推薦を行う。したがってユーザがアカウントを作ってくれないとそもそもレコメンドが出来ない問題がある。しかしアカウントがあれば特定のユーザにパーソナライズした推薦が可能となる。
一方で「アイテムベース」の推薦では「アイテム」に対して推薦を行うので上述の問題がない。しかしユーザについての情報が「ユーザが今見ているアイテム」しかないためパーソナライズが困難となる。
よってユーザの多くがアカウントを作っている(もしくはアカウント必須な)サービスであれば「ユーザベース」のほうが良いし、そうでないなら「アイテムベース」のほうが良く一長一短であるから両者を併用し状況によって使い分けるのが良い。


協調フィルタリングVSコンテンツマッチ
類似度計算の方式として「協調フィルタリング」と「コンテンツマッチ」どちらが良いのかを考えてみる。
まずは「協調フィルタリング」を考える。
「ユーザベース」は「ユーザ」に対して推薦するやり方なので「ユーザ」の情報が使えることが前提となる。つまり、そのサービスを初めて利用したユーザに対しては推薦をすることができない。なぜなら閲覧(購入)の情報が全くないからだ。しかしそのサービスを深く利用している「ユーザ」に対してはきめ細かい推薦が可能となる。
一方「アイテムベース」は「アイテム」に対する推薦をするため、初見のユーザに対しても推薦が行われる。しかし新商品に対しては「ユーザベース」と同様に閲覧(購入)情報が無いので推薦ができない。
以上のことから類似度計算に「協調フィルタリング」を用いた場合には「ユーザベース」では新規ユーザへの推薦が出来ず、「アイテムベース」では新アイテムの推薦が出来ないことがわかる。一方で十分な閲覧(購入)データがあれば適切な推薦が可能となる。
次に「コンテンツマッチ」を考える。
コンテンツマッチ」は「ユーザ」や「アイテム」の固有の情報を利用するため新ユーザ、新アイテムに依存しない推薦が可能となる。一方で閲覧(購入)の情報を利用しないので推薦結果が面白みのないものになる可能性がある。
よってサービス開始時は「コンテンツマッチ」方式を用いて、サービスが活性化してきたら「協調フィルタリング」方式に変更すると良い。
また「協調フィルタリング」に用いる情報としても閲覧情報よりも購入情報のほうが強い意味を持っているなど、情報にも良し悪しがあるので注意されたい。単純にデータが大きければ良いというものでもない。


大規模データがあれば良いレコメンデーションができるのか?
最近ではビッグデータでデータ(テキスト)マイニングだ!ひゃっはー!!!」という風潮がある。では本当に大規模データがあれば良いレコメンデーションができるのだろうか。レコメンデーションを導入する前にこの点について考えたい。結論から言うと、大規模データがあれば良いレコメンデーションができる場合がある。というのが私の意見。以下、詳細を述べる。
例えば「アイテム」が{焼き魚、ステーキ、納豆}の3種類あるとする。そしてユーザ3人{A,B,C}に対して推薦を行うのだがユーザには事前に{和食、洋食}のどちらが好きかを入力してもらっているとする。例えばユーザの好みが{A:和食、B:洋食、C:和食}だったときにユーザAに対してステーキを、ユーザBに対して焼き魚を推薦するようなシステムがあったとする。しかしこの推薦結果には不満がある。洋食が好きなユーザBにはステーキを推薦したい。推薦したいものがアイテムの中にあるのに推薦されていないのではあきらかに推薦がうまく機能していない。
ここでこの結果を見たエンジニアが「この推薦がうまくいっていないのは食べ物のデータが少なすぎるからですよ!データを増やしましょう!!!食べ物が100万種類あればすばらしいレコメンデーションができる気がするのです!!!」と言い出すかもしれない。このエンジニアは上述の「大規模データがあれば良いレコメンデーションができる」を鵜呑みにしていたのだ。
さて。冷静になって考えればわかるように食べ物が3種類でさえうまくいっていないものが100万種類に増えたところでうまくいくわけがない。この問題については食べ物にも{和食,洋食}の情報を付与してあげれば一瞬で解決する。これはあくまで一例だが、推薦がうまくいっていない言い訳として「大規模データでないから」ということを持ち出している場合がよくあるので注意されたい。
次のケースを考える。例えば「アイテム」が先程と同じく{焼き魚、ステーキ、納豆}の3種類あるとする。そして先程と同じく、ユーザ3人{A,B,C}に対して推薦を行う。しかし今度はユーザの好みの選択肢が{和食、洋食、中華}の3つの場合を考える。例えばユーザの好みが{A:和食、B:洋食、C:中華}だったとする。このときユーザCには何を推薦すれば良いのだろうか。焼き魚、ステーキ、納豆いずれも中華ではない。中華が好きなユーザCには中華料理を推薦したい。が、アイテムに麻婆豆腐などの中華料理はない。これでは推薦の仕組みが優れていても推薦のしようがない。
ここでこの結果を見たエンジニアが「この推薦がうまくいっていないのは食べ物のデータが少なすぎるからですよ!データを増やしましょう!!!食べ物が100万種類あればすばらしいレコメンデーションができる気がするのです!!!」と言い出すかもしれない。今回はこれは正しい(100万は言いすぎだが)。食べ物の種類を増やすことでユーザCが食べたいであろう麻婆豆腐などの中華料理がアイテムに加わる可能性が出てくる。
以上2つのケースを見てきたが、ポイントは小さいデータセットで考えたときにどういう推薦がされて欲しいかを言葉で表現してみること。これをすることで本当に大規模データが必要かどうかはある程度わかる。「言葉では表現できないのですがユーザに驚きを与えたいのです!セレンディピティが重要なのです!!大規模データがあれば実現できそうなのです!!」などという夢計画に対して正直に大規模データで試そうとするとたいてい泥沼にハマるので注意されたい。


まとめ
本記事ではレコメンドの種類と使い分けについて解説した。また大規模データの罠についても書いてみた。最近ではとにかく大規模データに目が行きがちだが、落ち着いて小さいデータを観察するところからレコメンデーションは始まるのだと思います(キリッ。