A.6.6.2 協調フィルタリングの概要および例
協調フィルタリング(ソーシャル・フィルタとも呼ばれる)は、他の人の推奨を使用して情報をフィルタリングします。協調フィルタリングは、似た好みを持つ他の人の購入内容に基づいて購入を推奨するシステムで広く使用されます。
次の例では、SQLベースの協調フィルタリング分析を示します。
例A-21 協調フィルタリングの設定および計算
この例では、SQLベースの協調フィルタリングの使用方法、具体的には、行列因子分解を使用した顧客への電話ブランドのお薦め方法を示します。この例では、データベース内に「PHONES」というグラフが存在すると想定しています。このグラフ例には、顧客頂点と品目頂点、および一部の顧客頂点を他の一部の品目頂点にリンクする「評価」ラベルを持つエッジが含まれています。評価ラベルには、特定の顧客(エッジOUT頂点)が、指定された商品(エッジIN頂点)に割り当てた評価に対応する数値があります。
次の図は、このグラフを示しています。
次のコードは、行列因子分解アルゴリズムを内部で使用する、SQLベースの協調フィルタリング・アルゴリズムを実行するためのエンドツーエンド・フローを示しています。set serveroutput on
DECLARE
  wt_l varchar2(32);  -- working tables
  wt_r varchar2(32);
  wt_l1 varchar2(32);
  wt_r1 varchar2(32);
  wt_i varchar2(32);
  wt_ld varchar2(32);
  wt_rd varchar2(32);
  edge_tab_name    varchar2(32) := 'phonesge$';
  edge_label       varchar2(32) := 'rating';
  rating_property  varchar2(32) := '';
  iterations       integer      := 100;
  min_error        number       := 0.001;
  k                integer      := 5;
  learning_rate    number       := 0.001;
  decrease_rate    number       := 0.95;
  regularization   number       := 0.02;
  dop              number       := 2;
  tablespace       varchar2(32) := null;
  options          varchar2(32) := null; 
BEGIN
  -- prepare
  opg_apis.cf_prep(edge_tab_name,wt_l,wt_r,wt_l1,wt_r1,wt_i,wt_ld,wt_rd);
  dbms_output.put_line('working table wt_l ' || wt_l);
  dbms_output.put_line('working table wt_r ' || wt_r);
  dbms_output.put_line('working table wt_l1 ' || wt_l1);
  dbms_output.put_line('working table wt_r1 ' || wt_r1);
  dbms_output.put_line('working table wt_i ' || wt_i);
  dbms_output.put_line('working table wt_ld ' || wt_ld);
  dbms_output.put_line('working table wt_rd ' || wt_rd);
  -- compute
  opg_apis.cf(edge_tab_name,edge_label,rating_property,iterations,
              min_error,k,learning_rate,decrease_rate,regularization,dop,
              wt_l,wt_r,wt_l1,wt_r1,wt_i,wt_ld,wt_rd,tablespace,options);
END;
/
working table wt_l "PHONESGE$$CFL57" working table wt_r "PHONESGE$$CFR57" working table wt_l1 "PHONESGE$$CFL157" working table wt_r1 "PHONESGE$$CFR157" working table wt_i "PHONESGE$$CFI57" working table wt_ld "PHONESGE$$CFLD57" working table wt_rd "PHONESGE$$CFRD57" PL/SQL procedure successfully completed.
例A-22 協調フィルタリング: 中間エラーの検証
作業表内のデータがまだ削除されていないかぎり、すべての計算の最後に次の問合せを使用してアルゴリズムの現在のエラーを確認できます。次のSQL問合せは、協調フィルタリング・アルゴリズムの現在の実行の中間エラーを取得する方法を示しています。
SELECT /*+ parallel(48) */ SQRT(SUM((w1-w2)*(w1-w2) + 
              <regularization>/2 * (err_reg_l+err_reg_r))) AS err 
  FROM <wt_i>;
正則化パラメータと作業表名(パラメータwt_i)は、OPG_APIS.CFアルゴリズムを実行しているときに使用される値に応じて置き換える必要があることに注意してください。前述の例では、次のように、<regularization>を0.02に置き換え、<wt_i>を「PHONESGE$$CFI149」に置き換えます。
                  
SELECT /*+ parallel(48) */ SQRT(SUM((w1-w2)*(w1-w2) + 0.02/2 * (err_reg_l+err_reg_r))) AS err 
  FROM "PHONESGE$$CFI149";
この問合せでは、次の出力が生成される可能性があります。
ERR ---------- 4.82163662
現在のエラーの値が大きすぎるか、協調フィルタリングの行列因子分解の結果から得た予想がまだ有用でない場合は、作業表とこれまでの進展を再利用して、アルゴリズムのさらなる反復を実行できます。次の例は、SQLベースの協調フィルタリングを使用した予測の実行方法を示しています。
例A-23 協調フィルタリング: 予測の実行
協調フィルタリング・アルゴリズムの結果が、行列積の2つの因子であるwt_l表とwt_r表に格納されます。協調フィルタリングの予測をする場合、これらの行列因子を使用する必要があります。
                  
このアルゴリズムの一般的なフローでは、OPG_APIS.CF_CLEANUPプロシージャをコールする前に、2つの行列因子を使用して予測を行うことができます。または、後で使用するために、それらを他の表にコピーして永続的なものにすることができます。次の例は、後者の場合を示しています。
DECLARE
  wt_l varchar2(32);  -- working tables
  wt_r varchar2(32);
  wt_l1 varchar2(32);
  wt_r1 varchar2(32);
  wt_i varchar2(32);
  wt_ld varchar2(32);
  wt_rd varchar2(32);
  edge_tab_name    varchar2(32) := 'phonesge$';
  edge_label       varchar2(32) := 'rating';
  rating_property  varchar2(32) := '';
  iterations       integer      := 100;
  min_error        number       := 0.001;
  k                integer      := 5;
  learning_rate    number       := 0.001;
  decrease_rate    number       := 0.95;
  regularization   number       := 0.02;
  dop              number       := 2;
  tablespace       varchar2(32) := null;
  options          varchar2(32) := null; 
BEGIN
  -- prepare
  opg_apis.cf_prep(edge_tab_name,wt_l,wt_r,wt_l1,wt_r1,wt_i,wt_ld,wt_rd);
  -- compute
  opg_apis.cf(edge_tab_name,edge_label,rating_property,iterations,
              min_error,k,learning_rate,decrease_rate,regularization,dop,
              wt_l,wt_r,wt_l1,wt_r1,wt_i,wt_ld,wt_rd,tablespace,options);
  
  -- save only these two tables for later predictions
  EXECUTE IMMEDIATE 'CREATE TABLE customer_mat AS SELECT * FROM ' || wt_l;
  EXECUTE IMMEDIATE 'CREATE TABLE item_mat AS SELECT * FROM ' || wt_r;
  -- cleanup
  opg_apis.cf_cleanup('phonesge$',wt_l,wt_r,wt_l1,wt_r1,wt_i,wt_ld,wt_rd);
END;
/
この例は、次の出力のみを生成します。
PL/SQL procedure successfully completed.
これで行列因子がcustomer_mat表とitem_mat表に保存されたので、次の問合せを使用して、実際の値(以前、「評価」としてグラフに存在していた値)と見積予想(特定の顧客行と品目列での行列の乗算の結果)の間の「エラー」(差分)を確認できます。
次の問合せは、数値IDではなく、頂点のNVARCHARプロパティ(たとえば、nameプロパティ)を返すために、頂点表で結合によってカスタマイズされていることに注意してください。この問合せは、グラフ内のすべての品目頂点に対するすべての顧客頂点のすべての予測を返します。
SELECT /*+ parallel(48) */ MIN(vertex1.v) AS customer, 
                           MIN(vertex2.v) AS item, 
                           MIN(edges.vn) AS real, 
                           SUM(l.v * r.v) AS predicted
FROM PHONESGE$ edges, 
      CUSTOMER_MAT l, 
      ITEM_MAT r, 
      PHONESVT$ vertex1,   
      PHONESVT$ vertex2
WHERE l.k = r.k
  AND l.c = edges.svid(+)
  AND r.p = edges.dvid(+)
  AND l.c = vertex1.vid
  AND r.p = vertex2.vid
GROUP BY l.c, r.p
ORDER BY l.c, r.p  -- This order by clause is optional
;
この問合せでは、次のような出力が生成される可能性があります(簡略化するために、一部の行は省略されています)。
CUSTOMER ITEM REAL PREDICTED ------------------------------------------------ Adam Apple 5 3.67375703 Adam Blackberry 3.66079652 Adam Danger 2.77049596 Adam Ericsson 4.21764858 Adam Figo 3.10631337 Adam Google 4 4.42429022 Adam Huawei 3 3.4289115 Ben Apple 2.82127589 Ben Blackberry 2 2.81132282 Ben Danger 3 2.12761307 Ben Ericsson 3 3.2389595 Ben Figo 2.38550534 Ben Google 3.39765075 Ben Huawei 2.63324582 ... Don Apple 1.3777496 Don Blackberry 1 1.37288909 Don Danger 1 1.03900439 Don Ericsson 1.58172236 Don Figo 1 1.16494421 Don Google 1.65921807 Don Huawei 1 1.28592648 Erik Apple 3 2.80809351 Erik Blackberry 3 2.79818695 Erik Danger 2.11767182 Erik Ericsson 3 3.2238255 Erik Figo 2.3743591 Erik Google 3 3.38177526 Erik Huawei 3 2.62094201
予測結果が準備できたか、アルゴリズムの反復をさらに実行する必要があるかどうかを判断するために一部の行のみを確認する場合は、外部問合せの中に前の問合せをラップできます。次の例では、最初の11個の結果のみが選択されます。
SELECT /*+ parallel(48) */ * FROM (
SELECT /*+ parallel(48) */ MIN(vertex1.v) AS customer, 
                           MIN(vertex2.v) AS item, 
                           MIN(edges.vn) AS real, 
                           SUM(l.v * r.v) AS predicted
FROM PHONESGE$ edges, 
     CUSTOMER_MAT l, 
     ITEM_MAT r, 
     PHONESVT$ vertex1,   
     PHONESVT$ vertex2
WHERE l.k = r.k
  AND l.c = edges.svid(+)
  AND r.p = edges.dvid(+)
  AND l.c = vertex1.vid
  AND r.p = vertex2.vid
GROUP BY l.c, r.p
ORDER BY l.c, r.p
) WHERE rownum <= 11;
この問合せでは、次のような出力が生成される可能性があります。
CUSTOMER ITEM REAL PREDICTED ------------------------------------------------ Adam Apple 5 3.67375703 Adam Blackberry 3.66079652 Adam Danger 2.77049596 Adam Ericsson 4.21764858 Adam Figo 3.10631337 Adam Google 4 4.42429022 Adam Huawei 3 3.4289115 Ben Apple 2.82127589 Ben Blackberry 2 2.81132282 Ben Danger 3 2.12761307 Ben Ericsson 3 3.2389595
特定の頂点(顧客、品目、またはその両方)の予測を取得するには、希望するID値によって問合せを制限できます。たとえば、頂点1(顧客)の予測値と頂点105(品目)の予測値を取得するには、次の問合せを使用できます。
SELECT /*+ parallel(48) */ MIN(vertex1.v) AS customer, 
                           MIN(vertex2.v) AS item, 
                           MIN(edges.vn) AS real, 
                           SUM(l.v * r.v) AS predicted
FROM PHONESGE$ edges, 
     CUSTOMER_MAT l, 
     ITEM_MAT r, 
     PHONESVT$ vertex1,   
     PHONESVT$ vertex2
WHERE l.k = r.k
  AND l.c = edges.svid(+)
  AND r.p = edges.dvid(+)
  AND l.c = vertex1.vid 
  AND vertex1.vid = 1 /* Remove to get all predictions for item 105 */
  AND r.p = vertex2.vid 
  AND vertex2.vid = 105 /* Remove to get all predictions for customer 1 */
                        /* Remove both lines to get all predictions */
GROUP BY l.c, r.p
ORDER BY l.c, r.p;
この問合せでは、次のような出力が生成される可能性があります。
CUSTOMER ITEM REAL PREDICTED ------------------------------------------------ Adam Ericsson 4.21764858
親トピック: SQLベース・プロパティ・グラフ分析
