Laravelで作成したアプリケーションにリコメンデーション機能を作ったときの備忘録
pythonじゃなくてもk近傍法(もどき)はできることにはできたが、pandas,numpyとか使えるPythonの方が触りやすいと思う。floatの精度問題とかもある。
前提
・複数の質問結果からアイテムをお勧めする
・質問はYes・No(ie, 0 or 1)
・初期データ入力可能
・実際の質問の回答結果を学習させより実態に沿ったお勧めにする
・お勧めするアイテム数がそこまで多くない(数百程度)
設計
1.お勧めに載せるアイテムごとに、質問結果のパターンを初期値として入力
2.回答パターンをベクトル成分([1,0,1,1,~,0])として捉える
$itemA = [1,0,1,1,1,0,~,1,0]
~
$itemN = [0,0,1,0,1,0,~,1,0]
3.実回答のベクトル成分とお勧め候補アイテムのユークリッド距離を計算し、近い順に取得しリコメンド
foreach($items as $coordinate_points) { // items = ["itemA" => [0,1,0,0....], "itemB" => [0,1,1,..] ... ]
$total = 0;
foreach($coordinate_points as $coordinate_point) {
$t += abs($coordinate_point - $actual_answer_point) ** 2
}
$euc_distance = $total ** 1/2
}
// $euc_distances = ["itemA" => 80, "itemB" => 14, ....]
4.実際に選択されたアイテムをリコメンド結果として取得、保存
5.お勧め候補アイテムの実選択データが一定数を超えたタイミングで、実回答群の重心を求め新たに該当アイテムの回答パターンとする。
// $merged_scores = ["q1" => [1,0,1,1,1], "q2" => [0,0,0,1,0] ...]
foreach ($merged_scores as $question_id => $coordinate_points) {
$new_coordinate_point = array_sum($coordinate_points) / $merged_scores->count(); //balance
if (!is_nan($new_coordinate_point)) { //prebend NaN
//update vector components
}
まとめ
限りなくシンプルな形で初期実装してみたけれど、外れ値を考慮していない点、全探索しているためリコメンドアイテム数が無数になる場合には向いてない点など多々問題点あり、試験的にこの形で実装してみて実データをとり相関とかを調べながら、より実態に即した形に変更していく必要がありそう。
そもそもの計算に関しても、リレーションを組めるならSQLでユークリッド距離計算をさせてしまった方が実は早い可能性もある。