協調フィルタリング推奨アルゴリズムを実装するには、まずアルゴリズムの中核となる考え方とプロセスを理解する必要があります。 このアルゴリズムの核となる考え方は次のように要約できます。 a と b が同じシリーズのアイテムを好む場合 (ここでは b を隣人と呼びましょう)、a は b が好む他のアイテムを好む可能性があります。アルゴリズムの実装プロセスは次のように簡単に要約できます。 1. a がどの近隣アイテムを持っているかを決定します。 2. その近隣アイテムを使用して、a が好むアイテムの種類を予測します。 3. a が好むアイテムを a に推奨します。
アルゴリズムの中心となる式は次のとおりです:
1. コサイン類似度 (近傍を見つける):
2. 予測式 (どのようなアイテムが好きかを予測):
のみこの 2 つの式から、これら 2 つの式に従って計算するだけでも多くのループと判断が必要であり、ソート アルゴリズムの選択と使用を含むソートの問題も含まれることがわかります。ここでは、クイック ソートを選択します。インターネットからクイック キューをコピーし、直接使用しました。つまり、ビッグデータの場合、効率化はもちろんのこと、導入するのが非常に面倒なのです。
最初に表を作成します:
DROP TABLE IF EXISTS `tb_xttj`; CREATE TABLE `tb_xttj` ( `name` varchar(255) NOT NULL, `a` int(255) default NULL, `b` int(255) default NULL, `c` int(255) default NULL, `d` int(255) default NULL, `e` int(255) default NULL, `f` int(255) default NULL, `g` int(255) default NULL, `h` int(255) default NULL, PRIMARY KEY (`name`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; INSERT INTO `tb_xttj` VALUES ('John', '4', '4', '5', '4', '3', '2', '1', null); INSERT INTO `tb_xttj` VALUES ('Mary', '3', '4', '4', '2', '5', '4', '3', null); INSERT INTO `tb_xttj` VALUES ('Lucy', '2', '3', null, '3', null, '3', '4', '5'); INSERT INTO `tb_xttj` VALUES ('Tom', '3', '4', '5', null, '1', '3', '5', '4'); INSERT INTO `tb_xttj` VALUES ('Bill', '3', '2', '1', '5', '3', '2', '1', '1'); INSERT INTO `tb_xttj` VALUES ('Leo', '3', '4', '5', '2', '4', null, null, null);
php+mysql を使用したフローチャートは次のとおりです:
データベースに接続し、2 次元配列として保存するコードは次のとおりです:
header("Content-Type:text/html;charset=utf-8"); mysql_connect("localhost","root","admin"); mysql_select_db("geodatabase"); mysql_query("set names 'utf8'"); $sql = "SELECT * FROM tb_xttj"; $result = mysql_query($sql); $array = array(); while($row=mysql_fetch_array($result)) { $array[]=$row;//$array[][]是一个二维数组 }
Leo らの Cos 値を見つけるコードは次のとおりです:
/* * 以下示例只求Leo的推荐,如此给变量命名我也是醉了;初次理解算法,先不考虑效率和逻辑的问题,主要把过程做出来 */ $cos = array(); $cos[0] = 0; $fm1 = 0; //开始计算cos //计算分母1,分母1是第一个公式里面 “*”号左边的内容,分母二是右边的内容 for($i=1;$i<9;$i++){ if($array[5][$i] != null){//$array[5]代表Leo $fm1 += $array[5][$i] * $array[5][$i]; } } $fm1 = sqrt($fm1); for($i=0;$i<5;$i++){ $fz = 0; $fm2 = 0; echo "Cos(".$array[5][0].",".$array[$i][0].")="; for($j=1;$j<9;$j++){ //计算分子 if($array[5][$j] != null && $array[$i][$j] != null){ $fz += $array[5][$j] * $array[$i][$j]; } //计算分母2 if($array[$i][$j] != null){ $fm2 += $array[$i][$j] * $array[$i][$j]; } } $fm2 = sqrt($fm2); $cos[$i] = $fz/$fm1/$fm2; echo $cos[$i]."<br/>"; }
取得した Cos 値を並べ替えて、次のようにクイック ソート コードを使用します (コピーしました) Baidu より):
//对计算结果进行排序,凑合用快排吧先 function quicksort($str){ if(count($str)<=1) return $str;//如果个数不大于一,直接返回 $key=$str[0];//取一个值,稍后用来比较; $left_arr=array(); $right_arr=array(); for($i=1;$i<count($str);$i++){//比$key大的放在右边,小的放在左边; if($str[$i]>=$key) $left_arr[]=$str[$i]; else $right_arr[]=$str[$i]; } $left_arr=quicksort($left_arr);//进行递归; $right_arr=quicksort($right_arr); return array_merge($left_arr,array($key),$right_arr);//将左中右的值合并成一个数组; } $neighbour = array();//$neighbour只是对cos值进行排序并存储 $neighbour = quicksort($cos);
CoS 値が最も高い 3 人をレオの隣人として選択します:
//$neighbour_set 存储最近邻的人和cos值 $neighbour_set = array(); for($i=0;$i<3;$i++){ for($j=0;$j<5;$j++){ if($neighbour[$i] == $cos[$j]){ $neighbour_set[$i][0] = $j; $neighbour_set[$i][1] = $cos[$j]; $neighbour_set[$i][2] = $array[$j][6];//邻居对f的评分 $neighbour_set[$i][3] = $array[$j][7];//邻居对g的评分 $neighbour_set[$i][4] = $array[$j][8];//邻居对h的评分 } } } print_r($neighbour_set); echo "<p><br/>";
これは 2 次元配列であり、配列の最初のレベルは 0、1、2 で、3 人を表します。第 2 レベルの添字 0 は、データ テーブル内の近隣者の順序を表します。たとえば、Jhon はテーブル内の 0 番目の人です。添字 1 は、レオと近隣者の Cos 値を表します。はそれぞれ隣接ペア f と g を表します。
予測を開始します。Predict の計算コードは次のとおりです。
レオの f、g、h の予測値をそれぞれ計算します。ここで問題となるのは、f、g、h のスコアが空の近傍がある場合にどう対処するかということです。たとえば、ジョンとメアリーによる h の評価は空です。直感的に if を使って判断し、空であればこの一連の計算をスキップしようと考えましたが、これが合理的かどうかは検討の余地があります。以下のコードはこのif判定を書いていません。
//计算Leo对f的评分 $p_arr = array(); $pfz_f = 0; $pfm_f = 0; for($i=0;$i<3;$i++){ $pfz_f += $neighbour_set[$i][1] * $neighbour_set[$i][2]; $pfm_f += $neighbour_set[$i][1]; } $p_arr[0][0] = 6; $p_arr[0][1] = $pfz_f/sqrt($pfm_f); if($p_arr[0][1]>3){ echo "推荐f"; } //计算Leo对g的评分 $pfz_g = 0; $pfm_g = 0; for($i=0;$i<3;$i++){ $pfz_g += $neighbour_set[$i][1] * $neighbour_set[$i][3]; $pfm_g += $neighbour_set[$i][1]; $p_arr[1][0] = 7; $p_arr[1][1] = $pfz_g/sqrt($pfm_g); } if($p_arr[0][1]>3){ echo "推荐g"; } //计算Leo对h的评分 $pfz_h = 0; $pfm_h = 0; for($i=0;$i<3;$i++){ $pfz_h += $neighbour_set[$i][1] * $neighbour_set[$i][4]; $pfm_h += $neighbour_set[$i][1]; $p_arr[2][0] = 8; $p_arr[2][1] = $pfz_h/sqrt($pfm_h); } print_r($p_arr); if($p_arr[0][1]>3){ echo "推荐h"; }
$p_arr は Leo に推奨される配列で、その内容は次のようになります。
Array ( [0] => Array ( [0] => 6 [1] => 4.2314002228795 ) [1] ] => ; 配列 ( [0] => 7 [1] => 2.6511380196197 ) [2] => 配列 ( [0] => 8 [1] => 0.45287424581774 ) )
f は最初の 6 です列、Predict 値は 4.23、g は 7 番目の列、Predict 値は 2.65...
f、g、h の Predict 値を計算した後、2 つの処理方法があります。1 つは Predict を使用する方法です。 value 値が 3 より大きいアイテムを Leo に推奨します。もう 1 つは、Predict 値を大きい順に並べ替え、Predict 値が大きい上位 2 つのアイテムを Leo に推奨することです。このコードは書かれていません。上記の例からもわかるように、推奨アルゴリズムの実装はループや判定、配列のマージなどが必要で非常に面倒です。適切に処理しないと、システムに負担がかかります。実際の処理にはまだ次の問題があります:
1. 上記の例では、Leo のみを推奨しており、Leo が f、g、h 項目を評価していないことがすでにわかっています。実際のシステムに導入した場合、推奨を行う必要があるユーザーごとに、どの項目が評価されていないのかを調べる必要があり、これもオーバーヘッドの一部となります。
2. 実際のシステムでは、テーブル全体のクエリを実行する必要はありません。いくつかの標準値を設定できます。例: テーブル内の Leo と他の人々の間の Cos 値を見つけます。その値が 0.80 より大きい場合、それらは隣人である可能性があることを意味します。このようにして、10 個の近傍が見つかったら、テーブル全体のクエリを回避するために Cos 値の計算を停止します。この方法は、たとえば、10 個のアイテムだけを推奨し、推奨した後は Predict 値の計算を停止するなど、推奨アイテムにも適切に使用できます。
3. システムを使用すると、項目も変更されます。今日は fgh、明日は xyz になる可能性があります。項目が変更されると、データ テーブルを動的に変更する必要があります。
4. コンテンツベースの推奨を適切に導入して、推奨アルゴリズムを改善できます。
5. 推奨される精度の問題。異なる標準値を設定すると精度に影響します。
要約: 本質的な問題は、アルゴリズムの効率が高くないことだと思います。研究を続けて、より優れた協調フィルタリング推奨アルゴリズムがあるかどうかを確認してください。
以上がphp+mysql協調フィルタリングアルゴリズムの実装の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。