<< PostgreSQL 8.3 リリース! 〜8.{1,2} と速度比較してみた〜 | main | RDB(関係データベース)の本質を知る 〜達人に学ぶ SQL徹底指南書〜 >>

リコメンデーション機能を実装する 〜Vogoo! PHP Lib〜

「この商品を買った人はこんな商品も買っています」
「○○さんへのおすすめ商品」

Amazon でよく見る例のアレ。

この機能を実装しなければならなくなったのですが, さてどうしたものか。
迷ったときのグーグル頼み, ということで早速ググると, このリコメンデーション(Recommendation)機能, 『協調フィルタリング』という手法で実現されているようです。

協調フィルタリング(Collaborative Filtering, CF)は、多くのユーザの嗜好情報を蓄積し、あるユーザと嗜好の類似した他のユーザの情報を用いて自動的に推論を行う方法論である。趣味の似た人からの意見を参考にするという口コミの原理に例えられることが多い。
(Wikipedia「協調フィルタリング」より)

ふむ。原理はなんとなくイメージが湧く。
けど実装するとなるとちと面倒くさそう。

何かいいライブラリがないかと探してみると, さくっと PHP での協調フィルタリングのライブラリが見つかりましたよ。
その名も Vogoo!(最後の ! は気分)

ブグー?ボグー?ボゴー?

何と読めばいいのかはさておき, 割と簡単に扱えそうでいい感じ。
導入実績もあるようなので早速コレを使ってみることにしよう。
Vogoo の基本的なアルゴリズムの流れは,

・アイテムの評価値を入力
・ある閾値を超える評価値のアイテム間全てに相互リンクを張る
・自分が高く評価したアイテムにリンクしているアイテムが推薦される

という感じ。

具体的な PHP のスクリプトで書くと,

$vogoo->set_rating($memberId, $itemId, $rateVal);
評価値を入力して(メンバー毎),

% php cronlinks.php
バッチ処理でアイテム間のリンクを計算して(メンバー毎),

$vogoo_items->member_get_recommended_items($memberId);
自分の趣向に合ったアイテムを評価値の高い順に取得する

という流れになります。

これで「○○さんへのおすすめ商品」の機能は実現できます。

“自分の趣向に合った”ということなので, たとえ A→B 間のリンク数が多い(多くの人が Aの評価が高い時, Bの評価も高い)場合でも, 自分が A を高く評価していなかったら B は推薦対象とはなりません。
ここら辺が協調(Collaborative)っぽい所です。

「この商品を買った人はこんな商品も買っています」の関連商品の提案機能は, 単純にアイテム間のリンク数で判断すれば実現できます。
A の関連商品は, 単純に A からのリンク数が多い順にアイテムを提案するだけです。
これは以下のように書けば OK 。

$vogoo_items->get_linked_items($itemId);


評価の閾値に基づくアイテム間のリンクを定義するやり方よりも, より正確性がある Slope One アルゴリズムを使うこともできます。

こちらを利用する場合は cronlink.php を cronslope.php に変更するだけです。
また, Slope One でしか使えないメソッドもあります。


と, 結構簡単にリコメンデーション機能が実現できる Vogoo PHP Lib ですが, フリー版は PostgreSQL と MySQL にしか対応していません。

今回は Oracle で使いたかったので, 修正して Oracle に対応するようにしたのですが...ソースが汚い汚いキタナイヨー。
最低限のメソッド化もされていない, まさに PHP ってな感じのソース。
修正自体はたいしたことなかったんですが, 見てて萎えました(;´∀`)

ライブラリは中見ないで使うだけが吉ですね。
もしかして有料版の Vogoo PHP Pro も中身こんなんなのか...

ロジックそのものは難しくないので, 興味がある方はソース読んでみて下さい。
データ突っ込んでテストしてみましたが, それっぽい感じの商品が推薦されて(る気がし)ました。
結果オーライ。

商品だけに限らず, ユーザが何らかの評価を与えられるオブジェクトなら Vogoo を使えるので色々応用できるかも知れません。

人工知能の話題:『協調フィルタリング』
ウノウラボ:『オススメ機能には Vogoo がオススメ』
はてブへ追加 この記事のはてブユーザ
Tech > Web | comments (6) | trackbacks (0) | pagetop↑

Comments

>y-110さん

返信どうもありがとうございます。
アドバイスを参考に色々な箇所を確認したところ、結果として
vogoo.phpの最後に記述してある
$vogoo = new vogoo_class($vg_dbhost,$vg_dbuser,$vg_dbpasswd,$vg_dbname);
の前にglobal $vogoo;をつけることによって解決できました。

おかげさまで全くの暗中模索だった中、解決までこぎつけることができました。
重ねて、ありがとうございました。


>sohさん

検証までしてくださりありがとうございました。
sohさんがちょうどいいタイミングで質問をなさっていたおかげで大きな助けになりました。
ありがとうございました。
T.E. | 2008/03/27 02:00 AM
>T.E.さん
items.php の 85行目でエラーになっているようですね。

if ( !($result = $vogoo->db->sql_query($sql)) )
...

$vogoo->db に正しくデータベースインスタンスが入っていないのが原因でしょう。

vogoo.php の 56行目で,

$this->db = new vg_sql_db($vg_dbhost,$vg_dbuser,$vg_dbpasswd,$vg_dbname,false);

のようにデータベースインスタンスを生成しているのですが, 恐らくここで失敗しているのだと思います。

MySQL を使っているとのことなので, db/mysql.php の vg_sql_dbコンストラクタ内をデバッグしてみてください。

@ でエラー表示抑制されている部分があるので, たぶんそこでエラーが出ていると思います。


>sohさん
テストがうまくいって何よりです。
vogoo は「協調フィルタリング」という性質上, 元データがある程度ないと値が返ってこないので, 実運用ではある程度評価データがたまってから, ですね。

商品間のリンク生成アルゴリズムはそんなに難しいことやってないので, 気になったらソースを覗いて見てください。
・・・ソースは汚いですが。
y-110 | 2008/03/26 10:27 AM
y-110様
早速のご返答、且つ非常に丁寧なご説明ありがとうございました。
確かにそれらしい値が返ってきました。
まだまだテスト段階ですので実用レベルにまで持っていくのには悪戦苦闘しそうですが、何とか初めの一歩を踏み出すことができました。

またわからないことがあれば質問させて頂くこともあるかと思いますので、よろしくお願い致します。

本当にありがとうございました!


T.E.様
ご質問の途中に失礼致しました。
エラーの内容を私も検証してみましたが、知識不足により解決することができませんでした。申し訳ありません。
soh | 2008/03/26 02:08 AM
はじめまして。便乗での質問失礼いたします。

先日vogooを導入したのですが、最初の段階で詰まってしまっております。

include('vogoo/vogoo.php');
$vogoo->set_rating($member_id, $contents_ID, 0.6);

等セットには成功し、テーブルにも期待通りに格納されているのを確認済みなのですが、

include('vogoo/items.php');
$recomended = $vogoo_items->member_get_recommended_items($u);

を実行すると、

Fatal error: Call to a member function sql_query() on a non-object in /home/htdocs/*****/*****/public_html/vogoo/items.php on line 85

のようなエラーが発生してしまいます。

だいぶ調べたのですが、どうにも解決策が見つからず質問させて頂きました。
基本的な問題で大変恐縮なのですが、何か解決の助けとなる情報等ありましたらご教示頂けると助かります。


環境は以下のようになっております。

FreeBSD 6.2-RELEASE-p4
PHP 5.2.5
MySQL 4.1.22

register_globals:On On
T.E. | 2008/03/25 01:09 PM
はじめまして。

>どのテーブルにどのようなデータを入力し、どのようなスクリプトで呼び出せばテストが可能なのか

こちらですが, 以下の手順で行います。

1. vogoo_rating テーブルにテストデータ挿入
2. cronlinks.php を実行
3. $vogoo_items->get_linked_items

テストデータを挿入する時の注意点としては,

・member_id と product_id は整数
・rating の値は 0〜1 の範囲

category の値は全て 1 で構いません。
ts のフィールドは NULL のままにしています。

soh さんがサイトで扱っている商品(?)に対するユーザからの評価値があると思うのですが, これは 0〜1 の範囲になるように調整します。

例えば, 評価が 1〜5点までつけられるような仕様なら, 評価を 5 で割った値を格納する感じです。

これらを踏まえてテストデータを生成するプログラムを作って適当なダミーデータを挿入します。

次に, cronlinks.php(clonslope.php でも可)を実行すると vogoo_linksテーブルに商品間のリンクデータが生成されます。

後は,

global $vogoo_items;
$vg_products = $vogoo_items->get_linked_items($itemId);

のように呼び出してやれば, $itemId に関連した商品ID 配列が返ってきます。

商品間のリンクではなく, ○○さんへのオススメ商品のような, あるユーザへのリコメンデーションの場合は,

global $vogoo_items;
$vg_products = $vogoo_items->member_get_recommended_items($memberId);

のようにユーザID を引数に member_get_recommended_items関数を呼んでやればオススメの商品ID 配列が返ってきます。
y-110 | 2008/03/24 07:03 PM
初めまして。
アマゾンのような「〜を購入した人はこんな商品も購入しています」というような機能を自分が運営するHP内に実装したく、調べていたら『Vogoo』に出会いました。
インストールをし、データベースの作成(vogoo_ads/vogoo_ads_products/vogoo_links/vogoo_ratingという4つのテーブルの作成)までは上手くいったのですが、英語が苦手で且つプログラムに関しては素人なためどのテーブルにどのようなデータを入力し、どのようなスクリプトで呼び出せばいいのかがわかりません。

>>データ突っ込んでテストしてみましたが, それっぽい感じの商品が推薦されて(る気がし)ました。

ということでしたので、どのテーブルにどのようなデータを入力し、どのようなスクリプトで呼び出せばテストが可能なのかご享受頂けませんでしょうか?

是非お力添えを頂きたく。
よろしくお願い致します。

開発環境は以下になります。
OS:MacOS10.5
PHP:php5.2.4
データベース:MySQL4.1.22
soh | 2008/03/24 03:53 AM

Post your Comment

Trackbacks