EC サイトで買い物中、 こんなブロックを見たことがあるはずです:
これらは レコメンデーション(推薦システム) の出力です。 ユーザーごとに膨大なアイテム(数百万〜数億)の中から、「この人が好みそうな数件」 を上位に並べることで、 ユーザー体験と売上を同時に押し上げます。 GAFAM、 Netflix、 Spotify、 TikTok、 メルカリ……現代のあらゆるサービスの中核技術です。
コサイン類似度、 Pearson 相関、 Jaccard 係数 などが頻出。 距離が近い=好みが似ている。Precision@K、 Recall@K、 nDCG、 MAP、 RMSE(評価値予測の場合)など。レコメンデーションの仕組みを、 一言で言うと:
たとえば「あなた」「友達 A」「友達 B」の 3 人が、 過去にこんな映画評価をしていたとします:
| ユーザー | 千と千尋 | ジョーズ | ラブ・アクチュアリー | マッドマックス |
|---|---|---|---|---|
| あなた | ★5 | ★2 | ★4 | ? |
| 友達 A | ★5 | ★1 | ★5 | ★1 |
| 友達 B | ★1 | ★5 | ★1 | ★5 |
3 作品ぶんの評価から、 「あなた」は友達 A と嗜好が近く、 友達 B とは正反対 だと分かります。 友達 A は「マッドマックス」に ★1 をつけているので、 「あなた」にも「マッドマックスは合わない」と推薦しない のが妥当な判断。
「協調フィルタリング」とは、 まさにこの 「似た嗜好の人が高評価したものをあなたにも推薦する」 作業を、 数百万ユーザー × 数百万アイテムでスケールさせる手法です。
| 方式 | 類似度の元データ | 強み | 弱み |
|---|---|---|---|
| 協調フィルタリング (Collaborative Filtering) |
ユーザーの行動履歴(評価、 購入、 クリック) | アイテムの中身を知らなくてもよい/意外な発見がある | 新規ユーザー・新規アイテムに弱い(コールドスタート) |
| コンテンツベース (Content-Based) |
アイテムの属性(ジャンル、 タグ、 テキスト埋め込み) | 新規アイテムでもすぐ推薦可能/説明が容易 | 過去の嗜好の 狭い範囲 にしか推薦できない(飽きやすい) |
| ハイブリッド (Hybrid) |
行動 + 属性 + 文脈 | 両方の弱みを補える/実用システムの主流 | 実装が複雑/チューニングコスト大 |
ユーザー $u$ がまだ評価していないアイテム $i$ について、 評価値 $\hat{r}_{u,i}$ を予測します:
類似度 $\mathrm{sim}(u, v)$ には コサイン類似度 または Pearson 相関 が頻用されます。 コサイン類似度の定義は:
巨大なユーザー × アイテム評価行列 $R \in \mathbb{R}^{m \times n}$ を、 2 つの低次元行列に分解します:
Netflix Prize(2006-2009、 賞金 100 万 USD)で SVD ベースの行列分解が圧勝して以来、 業界標準の 1 つになりました。
ユーザーベース CF の予測式 $\hat{r}_{u,i} = \bar{r}_u + \sum_v \mathrm{sim}(u,v)(r_{v,i} - \bar{r}_v) / \sum_v |\mathrm{sim}(u,v)|$ を分解します。
要するに:「自分の平均評価点」を起点に、 「似た人が普段より高評価/低評価したぶんを類似度で重み付け平均して足す」――これが協調フィルタリングの核心です。
本来のレコメンデーションは「ユーザー × アイテム」の関係ですが、 教育的アナロジーとして 「都道府県 = ユーザー」「社会指標 = アイテム」 と見立て、 「東京と嗜好(指標プロファイル)が似た県」を推薦してみます。 SSDSE-B-2026 から 5 指標 × 5 県を抜粋:
| 県 | 人口(万人) | 大学進学率(%) | 持家率(%) | 平均所得(万円) | 高齢化率(%) |
|---|---|---|---|---|---|
| 東京 | 1404 | 72.8 | 45.0 | 568 | 22.8 |
| 神奈川 | 923 | 67.5 | 59.3 | 421 | 25.7 |
| 大阪 | 880 | 64.2 | 54.7 | 373 | 27.9 |
| 秋田 | 93 | 49.8 | 78.4 | 248 | 39.1 |
| 沖縄 | 147 | 40.5 | 44.4 | 234 | 22.8 |
各県を 5 次元ベクトルとして扱い、 標準化してからコサイン類似度 を計算します(生の値だと「人口」の桁が他指標を支配するため)。
解釈:もし「東京の人」を 47 都道府県のどれかに 1 つ「住み替え推薦」したいなら、 ライフスタイルが最も近い 神奈川 が筆頭候補。 これが コンテンツベース 推薦(属性ベクトルの類似度)の最小例です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import pandas as pd import numpy as np from sklearn.preprocessing import StandardScaler from sklearn.metrics.pairwise import cosine_similarity # データ読込 df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1) # 都道府県名を index に、 最新年の数値列のみ抽出 df_latest = df[df['年度'] == df['年度'].max()].copy() df_latest = df_latest.set_index('都道府県') features = df_latest.select_dtypes(include=[np.number]) features = features.dropna(axis=1) # 欠損列を落とす print(features.shape) # 例: (47, 100+) print(features.head()) |
1 2 3 4 5 6 7 8 9 10 11 | # Z 標準化(指標の単位を揃える) scaler = StandardScaler() X = scaler.fit_transform(features) # コサイン類似度行列(47×47) sim_matrix = cosine_similarity(X) sim_df = pd.DataFrame(sim_matrix, index=features.index, columns=features.index) print(sim_df.loc['東京都'].sort_values(ascending=False).head(10)) # 自分自身を除いた上位5県を表示 print(sim_df.loc['東京都'].drop('東京都').sort_values(ascending=False).head(5)) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 仮に 5 指標を「アイテム」と見立てて評価値行列を構築 items = ['人口', '大学進学率', '持家率', '平均所得', '高齢化率'] R = features[items].copy() # 47×5 の「評価行列」 # 行ごと平均を引いて平均中心化 R_centered = R.sub(R.mean(axis=1), axis=0) # 県間類似度(ユーザー類似度) user_sim = cosine_similarity(R_centered.fillna(0)) user_sim = pd.DataFrame(user_sim, index=R.index, columns=R.index) # 東京の「大学進学率」を伏せて、 上位 5 近傍から予測してみる target_user = '東京都' target_item = '大学進学率' neighbors = user_sim[target_user].drop(target_user).sort_values(ascending=False).head(5) num = sum(neighbors[v] * (R.loc[v, target_item] - R.loc[v].mean()) for v in neighbors.index) den = neighbors.abs().sum() pred = R.loc[target_user].mean() + num / den print(f'予測値: {pred:.1f}, 実測値: {R.loc[target_user, target_item]:.1f}') |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # pip install scikit-surprise from surprise import Dataset, Reader, KNNBasic, SVD from surprise.model_selection import cross_validate # 仮想「県 × 指標 × 値」のロング形式を作る long_df = R.stack().reset_index() long_df.columns = ['user', 'item', 'rating'] reader = Reader(rating_scale=(long_df['rating'].min(), long_df['rating'].max())) data = Dataset.load_from_df(long_df[['user','item','rating']], reader) # ユーザーベース kNN algo = KNNBasic(sim_options={'name':'cosine','user_based':True}) cross_validate(algo, data, measures=['RMSE','MAE'], cv=3, verbose=True) # 行列分解(SVD) svd = SVD(n_factors=10, n_epochs=20, random_state=0) cross_validate(svd, data, measures=['RMSE','MAE'], cv=3, verbose=True) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | def precision_at_k(recommended, relevant, k): rec_k = recommended[:k] return len(set(rec_k) & set(relevant)) / k def recall_at_k(recommended, relevant, k): rec_k = recommended[:k] return len(set(rec_k) & set(relevant)) / len(relevant) if relevant else 0.0 def dcg_at_k(scores, k): return sum((2**s - 1) / np.log2(i + 2) for i, s in enumerate(scores[:k])) def ndcg_at_k(recommended_scores, ideal_scores, k): dcg = dcg_at_k(recommended_scores, k) idcg = dcg_at_k(sorted(ideal_scores, reverse=True), k) return dcg / idcg if idcg > 0 else 0.0 # 例:東京の Top5 推薦が「神奈川, 大阪, 愛知, 千葉, 埼玉」、 正解が「神奈川, 千葉, 兵庫」 rec = ['神奈川', '大阪', '愛知', '千葉', '埼玉'] rel = ['神奈川', '千葉', '兵庫'] print('Precision@5:', precision_at_k(rec, rel, 5)) # 0.4 print('Recall@5:', recall_at_k(rec, rel, 5)) # 0.667 |
レコメンデーションの主要なバリエーション:
| 手法 | 仕組み | 代表的な用途 |
|---|---|---|
| ユーザーベース CF | 類似ユーザー → 推薦 | SNS、 友達推薦 |
| アイテムベース CF | 類似アイテム → 推薦(Amazon の元祖) | EC「この商品を見た人は…」 |
| 行列分解(MF, SVD) | 低次元潜在因子の積で再構成 | Netflix Prize 優勝手法 |
| ニューラル CF (NCF) | 埋め込み + MLP で柔軟な相互作用学習 | YouTube, TikTok |
| Two-Tower モデル | ユーザー塔・アイテム塔の埋め込み内積 | Google, Pinterest |
| Wide & Deep | 記憶(線形)+ 汎化(DNN)の組合せ | Google Play |
| シーケンシャル推薦 | RNN/Transformer で行動系列を考慮 | SASRec, BERT4Rec |
| 多腕バンディット | 探索と活用のバランスでオンライン学習 | ニュース推薦、 広告 |
| 強化学習ベース | 長期報酬最大化を直接最適化 | 動画視聴時間最大化 |
| グラフベース推薦 | ユーザー・アイテム二部グラフ + GNN | PinSage, LightGCN |
本サイトでは コサイン類似度 や k-means クラスタリング が推薦の前処理として登場します。 また、 主成分分析 は行列分解の親戚(SVD ≒ 中心化後の PCA)であり、 推薦の根底技術と密接に関係します。
推薦システムは多くの統計・機械学習技術が交わる十字路です。 全体像を 1 枚にまとめました。
| レイヤー | 主な技術 | 本サイトの関連用語 |
|---|---|---|
| 0. データ層 | ユーザー行動ログ/アイテムメタデータ/コンテキスト | データパイプライン、 特徴量エンジニアリング |
| 1. 類似度層 | コサイン/Pearson/Jaccard/編集距離 | コサイン類似度、 相関係数、 距離 |
| 2. モデル層 | kNN/行列分解/NCF/Two-Tower/GNN | k-NN、 PCA/SVD、 ニューラルネット |
| 3. 評価層 | Precision/Recall@K/nDCG/MAP/RMSE/オンライン A/B | Precision-Recall、 A/B テスト |
| 4. デプロイ層 | 候補生成(recall)+ リランキング/キャッシュ/フィードバックループ | MLOps、 監視 |
典型的な大規模本番推薦システムは、 2 段階アーキテクチャで構築されます:
さらに 事後処理(Post-Processing) として多様性、 ビジネスルール、 公平性制約を適用してから最終リストを返します。
推薦の評価指標は 「予測誤差系」(RMSE, MAE)と 「ランキング系」(Precision@K, Recall@K, nDCG, MAP, MRR)に大別されます。 現代の業界標準はほぼランキング系です。
| 指標 | 計算式(概略) | 意味 | 用途 |
|---|---|---|---|
| RMSE | $\sqrt{\frac{1}{N}\sum(r_{u,i} - \hat{r}_{u,i})^2}$ | 評価値の予測誤差 | Netflix Prize 時代の標準 |
| Precision@K | (K 件中の正解数) / K | 上位 K 件のうち適合率 | 「最初の画面に何個刺さるか」 |
| Recall@K | (K 件中の正解数) / (全正解数) | 正解アイテムを取り逃さない率 | 候補生成段階で重視 |
| nDCG@K | DCG@K / IDCG@K | 「順位の重み」を考慮した適合度 | ランキング全般の標準 |
| MAP | 各ユーザー AP の平均 | 平均適合率 | 情報検索由来、 学術論文で頻出 |
| MRR | $\frac{1}{N}\sum \frac{1}{\text{rank}_{\text{first hit}}}$ | 最初の正解の順位逆数 | 1 件目に正解を出したい用途(QA、 検索) |
| Coverage | (推薦されたユニーク・アイテム数) / (全アイテム数) | カタログのどれだけを使えているか | ロングテール多様性 |
| Diversity | $1 - \mathrm{avg}(\mathrm{sim}(i, j))$ | 推薦リスト内の類似度の低さ | 飽き防止 |
| Novelty | $-\log_2(\text{popularity})$ | 「珍しさ」 | セレンディピティ評価 |
| Serendipity | 意外性 × 適合性 | 「意外なのに刺さる」 | 長期ユーザー満足度 |
nDCG(normalized Discounted Cumulative Gain)は 順位による割引を入れた指標です:
例:5 件推薦して関連度が [3, 2, 0, 1, 2] だったとき:
| 時期 | 転換点 | 意義 |
|---|---|---|
| 1992 | Tapestry(Xerox PARC)— 協調フィルタリングの語誕生 | メール推薦システムで、 他人のフィードバックを使う最初の試み |
| 1994 | GroupLens — ニュース推薦の Pearson 相関 CF | 明示的フィードバック × ユーザーベース CF の原型 |
| 2003 | Amazon — アイテムベース CF を学術論文化 | スケーラビリティの壁を突破、 EC の標準に |
| 2006-2009 | Netflix Prize — 行列分解の優勝 | SVD、 NMF、 アンサンブルが業界標準化 |
| 2016-現在 | Deep Learning 推薦(NCF, Two-Tower, GNN, Transformer) | Google, YouTube, TikTok, Pinterest が DL ベースに移行 |
Netflix Prize 優勝アルゴリズムの中核技術。 ユーザー × アイテム評価行列 $R$ を 2 つの低次元行列に分解します:
各観測 $(u, i, r_{u,i})$ ごとに:
$\eta$=学習率(0.005〜0.05 程度)。 数十エポックで収束。 全観測を 1 度なめるごとに 1 エポック。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | import numpy as np # 観測リスト: [(user_id, item_id, rating), ...] n_users, n_items, k = 47, 100, 8 eta, lam, n_epochs = 0.01, 0.05, 50 P = np.random.normal(0, 0.1, (n_users, k)) Q = np.random.normal(0, 0.1, (n_items, k)) bu = np.zeros(n_users) bi = np.zeros(n_items) mu = np.mean([r for _,_,r in observations]) for epoch in range(n_epochs): np.random.shuffle(observations) sse = 0 for u, i, r in observations: pred = mu + bu[u] + bi[i] + P[u] @ Q[i] e = r - pred sse += e**2 bu[u] += eta * (e - lam * bu[u]) bi[i] += eta * (e - lam * bi[i]) P[u] += eta * (e * Q[i] - lam * P[u]) Q[i] += eta * (e * P[u] - lam * Q[i]) rmse = np.sqrt(sse / len(observations)) if epoch % 10 == 0: print(f'Epoch {epoch}: RMSE={rmse:.4f}') # 推薦: ユーザー u の未観測アイテムスコア def recommend(u, observed_items, top_n=10): scores = mu + bu[u] + bi + P[u] @ Q.T scores[list(observed_items)] = -np.inf return np.argsort(-scores)[:top_n] |
現実のサービスでは、 ユーザーが ★1〜5 のような明示的な評価 をしてくれることは稀です。 代わりに 暗黙的なシグナル(クリック、 滞在時間、 購入、 視聴完走率、 スクロール深度、 再生スキップ等)を学習信号として使います。
| 項目 | 明示的フィードバック | 暗黙的フィードバック |
|---|---|---|
| 例 | ★1〜5、 👍👎、 レビュー | クリック、 購入、 滞在時間、 再生時間 |
| 量 | 少ない(積極的なユーザーのみ) | 圧倒的に多い(全行動が信号) |
| 意味の明確さ | はっきり「好き/嫌い」 | 「クリックしたが嫌いだった」可能性も |
| 負例 | 低評価が「負例」として明示 | 「見なかった」のは「興味なし」と「知らなかった」が混在 |
| 代表的手法 | SVD、 BiasMF、 SVD++ | ALS(Alternating Least Squares)、 BPR(Bayesian Personalized Ranking) |
暗黙的フィードバック用に Koren ら(2008)が提案した古典的手法:
P と Q を交互に固定して最小二乗で解くため SGD より並列化しやすく、 Spark MLlib などで大規模実装が確立されています。
Rendle ら(2009)が提案した ペアワイズ学習 アプローチ。 「観測済アイテム i は未観測アイテム j より好まれるはず」をベイズ的最尤推定で学習:
推薦システムは 「誰に何を見せるか」 を決める強力な装置。 副作用として以下の倫理的問題が議論されています:
これまでの議論を踏まえ、 SSDSE-B-2026 全 47 都道府県を使った End-to-End 推薦パイプライン を構築します。 「都道府県=ユーザー」「指標=アイテム」のアナロジーを最後まで突き詰めます。
pd.read_csv('data/raw/SSDSE-B-2026.csv')1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | import pandas as pd import numpy as np from sklearn.preprocessing import StandardScaler from sklearn.metrics.pairwise import cosine_similarity # === 1. データ取得 === df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1) # === 2. 前処理:最新年抽出 + 数値列のみ === df = df[df['年度'] == df['年度'].max()].copy() df = df.set_index('都道府県') X_raw = df.select_dtypes(include=[np.number]).dropna(axis=1) # === 3. 標準化 === scaler = StandardScaler() X = scaler.fit_transform(X_raw) # === 4. 全県間コサイン類似度(47×47)=== sim = cosine_similarity(X) sim_df = pd.DataFrame(sim, index=X_raw.index, columns=X_raw.index) # === 5. 各県への推薦 Top 5 === def recommend(pref_name, k=5): s = sim_df[pref_name].drop(pref_name) return s.sort_values(ascending=False).head(k) print('東京都への推薦:') print(recommend('東京都')) print() print('秋田県への推薦:') print(recommend('秋田県')) print() print('沖縄県への推薦:') print(recommend('沖縄県')) # === 6. 評価:地理的隣県を正解と仮定(テスト用)=== # 簡易的に「同じ地方ブロックの県」を正解と定義 chiho = { '東京都': ['神奈川県','千葉県','埼玉県','茨城県','栃木県','群馬県','山梨県'], '大阪府': ['京都府','兵庫県','奈良県','和歌山県','滋賀県'], '沖縄県': ['鹿児島県','宮崎県','熊本県','長崎県','大分県','佐賀県','福岡県'], } def precision_at_k(pref, k=5): rec = recommend(pref, k).index.tolist() rel = chiho.get(pref, []) if not rel: return None return len(set(rec) & set(rel)) / k for p in chiho: print(f'{p}: Precision@5 = {precision_at_k(p):.2f}') # === 7. MMR でリランキング(多様性を入れる)=== def mmr_rerank(target, candidates, lambda_=0.7, k=5): selected = [] remaining = list(candidates) while len(selected) < k and remaining: best, best_score = None, -np.inf for c in remaining: relevance = sim_df.loc[target, c] diversity = 0 if not selected else max(sim_df.loc[c, s] for s in selected) score = lambda_ * relevance - (1 - lambda_) * diversity if score > best_score: best_score, best = score, c selected.append(best) remaining.remove(best) return selected # 候補を Top 15 から、 多様性 30% で再ランキングして Top 5 を取り直し candidates = recommend('東京都', k=15).index.tolist() diversified = mmr_rerank('東京都', candidates, lambda_=0.7, k=5) print('東京都 多様化リランキング Top5:', diversified) |
| ターゲット県 | Top 5 推薦結果(解釈) |
|---|---|
| 東京都 | 神奈川 → 大阪 → 愛知 → 千葉 → 埼玉(大都市・高所得・低持家率という都市プロファイル) |
| 秋田県 | 青森 → 山形 → 岩手 → 高知 → 島根(東北+人口減少高齢化県群) |
| 沖縄県 | 宮崎 → 鹿児島 → 高知 → 熊本 → 長崎(九州南部+低所得+若年層比率高め) |
| 愛知県 | 静岡 → 三重 → 神奈川 → 大阪 → 兵庫(製造業中心+大都市圏隣接) |
面白い発見:単純なコサイン類似度だけでも、 地理的隣県・経済規模・人口構造 がうまく反映されています。 たとえば「秋田 → 高知・島根」のように、 地理は離れていても 「人口減少・高齢化が急速」という共通プロファイル が浮かび上がる。 これがレコメンデーションの面白さです。
$\lambda = 1.0$ では純粋にコサイン類似度順、 $\lambda = 0.0$ では最も既選択と異なるものを選ぶ。 中間で関連性と多様性のバランスを取ります。
純粋な協調フィルタリングやコンテンツベースだけでは限界があるため、 実務システムではほとんどが ハイブリッド設計を採用しています。 主要な組み合わせパターン:
| パターン | 仕組み | 長所 |
|---|---|---|
| ① 重み付き混合(Weighted) | $\text{score} = \alpha \cdot \text{CF} + (1-\alpha) \cdot \text{CB}$ | シンプル、 解釈可能 |
| ② スイッチング(Switching) | 状況により CF or CB を選択 | コールドスタート時は CB、 充実後は CF |
| ③ 混合(Mixed) | 複数モデルの結果を並べて表示 | 多様性確保、 比較しやすい |
| ④ 特徴量結合(Feature Combination) | CB の属性を CF の特徴量に追加 | 属性情報も学習に活用 |
| ⑤ カスケード(Cascade) | 段階的に絞り込み(candidate gen → ranking) | 大規模向け、 計算効率良い |
| ⑥ メタレベル(Meta-level) | 1 モデルの出力を別モデルの入力に | 複雑な相互作用を学習 |
| ⑦ アンサンブル(Ensemble) | 複数モデルの結果を加重平均 | Netflix Prize 優勝の鍵 |
2009 年に賞金 100 万 USD を獲得した「BellKor's Pragmatic Chaos」チームは、 100+ 種類の異なるモデルをアンサンブルしていました。 内訳の例:
この勝利は、 単一モデルの最適化より 「多様なモデルの組み合わせ」がより強力という教訓を残しました。
候補生成では Two-Tower モデルや近似最近傍検索(ANN; FAISS, ScaNN)、 リランキングでは GBDT(LightGBM, XGBoost)や DNN を多用。 YouTube、 TikTok、 Pinterest など主要プラットフォームの推薦システムはこのパターン。
| 失敗 | 原因 | 対策 |
|---|---|---|
| 新ユーザーに何も推薦できない | コールドスタート未対策 | 人気アイテム、 アンケート、 コンテンツベース |
| 「面白くない推薦ばかり」 | 過度のパーソナライズ | 多様性、 セレンディピティを KPI に |
| マイナー商品が永遠に売れない | 人気バイアスのフィードバックループ | 人気度逆数重み、 探索率の確保 |
| オフラインで好成績、 本番で失敗 | 評価指標とビジネス KPI の乖離 | A/B テストを最初から |
| 推薦サーバが落ちる | レイテンシ・スケーラビリティ未考慮 | キャッシュ、 ANN、 マイクロサービス化 |
推薦システムは 「数億人の毎日の選択」を方向付ける強力な装置です。 技術的問題だけでなく、 社会的・倫理的影響も計算に入れた設計が求められています。
2018 年、 Amazon の社内採用 AI で「女性応募者を不利に評価する」バイアスが発覚し、 同社は AI 採用を中止しました。 これは過去の採用データ(男性偏重)を学習したことが原因。 推薦システムでも同じ問題が頻発:
| 指標 | 定義 | 意味 |
|---|---|---|
| Demographic Parity | $P(\hat{Y}=1 | A=0) = P(\hat{Y}=1 | A=1)$ | 属性 A によらず推薦率が同じ |
| Equal Opportunity | $P(\hat{Y}=1 | Y=1, A=0) = P(\hat{Y}=1 | Y=1, A=1)$ | 真の好みが同じなら推薦率も同じ |
| Calibration | 予測スコアが属性によらず実確率と一致 | スコアの解釈が公平 |
| Counterfactual Fairness | 「属性が違ったら推薦も違うか?」を反実仮想で評価 | 因果的に公平 |
推薦の精度とユーザープライバシーは相反する側面があります:
「なぜこれが推薦されたか」を説明する技術。 EU GDPR では「自動化された決定の説明を受ける権利」が明文化されました。
レコメンデーションは 「機械学習応用」「情報検索」 のグループに属します。 同カテゴリの教材:
レコメンデーションシステムは 協調フィルタリング・コンテンツベース・ハイブリッドの三大流派に分かれます。 SSDSE-B-2026 の都道府県データを使うと、 「東京に似た県を推薦」のような直感的タスクで原理が学べます。
$$\hat r_{u,i} = \bar r_u + \frac{\sum_{v \in N_u} \mathrm{sim}(u,v)(r_{v,i} - \bar r_v)}{\sum_{v \in N_u} |\mathrm{sim}(u,v)|}$$
上式はユーザーベース協調フィルタリングの予測式。 ユーザー $u$ が商品 $i$ に付ける評価を、 「$u$ と似た他ユーザー $v$ の評価」の重み付き平均で予測します。
| 手法 | 入力 | 長所 | 短所 |
|---|---|---|---|
| User-based CF | 評価行列 | シンプル・解釈容易 | 新規ユーザー困難 |
| Item-based CF | 評価行列 | スケーラブル | 長尾商品弱い |
| Matrix Factorization | 評価行列 | 欠損対応 | コールドスタート |
| Content-based | 商品属性 | コールド対応 | 多様性低い |
| Hybrid | 混合 | 長所統合 | 実装複雑 |
| Deep Learning | 系列・画像 | 非線形・多モーダル | データ大量必要 |
Netflix Prize (2006-2009) で Matrix Factorization が王者になり、 その後 Deep Learning ベース (NCF, Two-Tower) が主流に。
Cold Start 問題への対処:
Q. User-based と Item-based、 どっち?
A. 一般にユーザー数 < 商品数なら User-based、 逆なら Item-based。 Amazon は Item-based で有名(商品安定性が高い)。 SSDSE-B-2026 で 47 都道府県(少数)vs 100+ 指標(多数)なら User-based。
Q. Matrix Factorization の k は?
A. 通常 10-200。 データのスパース性と過適合のバランス。 MovieLens では k=50 が定番、 Netflix は k=200 程度。
Q. Cold Start を完全解決する方法は?
A. 完全解決は不可能ですが、 (1) コンテンツベース fallback、 (2) デモグラフィック類似、 (3) Active Learning、 (4) Meta-Learning などで緩和。
Q. Deep Learning は必須?
A. 大規模・複雑データ(画像・系列)には有効。 中小規模では Matrix Factorization が依然強力。 解釈性とコストを天秤に。
Q. Implicit feedback はどう扱う?
A. クリック・閲覧・購入の二値化、 または時間・回数で重み付け。 Weighted ALS (Hu et al., 2008) が標準。
Q. 評価指標は?
A. Precision@K / Recall@K / nDCG / MAP / Hit Rate。 ビジネス指標としては CTR、 conversion rate、 LTV。
Amazon
商品レコメンデーション、 Item-based CF + Deep Learning。
Netflix
映画・ドラマ推薦、 Matrix Factorization + Personalization。
YouTube
動画推薦、 Two-Tower + Multi-Armed Bandit。
Spotify
音楽推薦、 Audio Embedding + 協調フィルタリング。
TikTok
ショート動画推薦、 強化学習ベース。
人材マッチング、 グラフベース。
画像推薦、 Visual Embedding。
Booking.com
ホテル推薦、 リアルタイム個別化。