LESSON

コンテンツベース推薦

「協調フィルタリングは新商品に弱い。誰も買っていない商品は推薦できないからな。」

田中VPoEがNetShop社の新商品リストを開く。

「毎週100点以上の新商品が入荷するのに、行動データが貯まるまで推薦できないのは機会損失だ。商品の中身で推薦するアプローチも必要だ。」

コンテンツベース推薦の基本原理

コンテンツベース推薦(Content-Based Filtering)は、アイテムの属性情報(特徴量)を使って類似アイテムを推薦する手法である。ユーザーが過去に好んだアイテムの特徴を分析し、類似した特徴を持つ未見のアイテムを推薦する。

協調フィルタリングとの比較

観点協調フィルタリングコンテンツベース
入力データ行動データのみアイテム属性
Cold Start新規アイテムに弱い新規アイテムでも推薦可能
セレンディピティ高い低い(似たものばかり)
ドメイン知識不要特徴量設計に必要
データの疎性影響大影響小

特徴量抽出

カテゴリ特徴量

import pandas as pd
from sklearn.preprocessing import MultiLabelBinarizer

# 商品データ
products = pd.DataFrame({
    'product_id': [1, 2, 3, 4, 5],
    'name': ['ランニングシューズA', 'ランニングシューズB', '革靴C', 'スニーカーD', 'ブーツE'],
    'category': ['シューズ', 'シューズ', 'シューズ', 'シューズ', 'シューズ'],
    'sub_category': ['ランニング', 'ランニング', 'ビジネス', 'カジュアル', 'アウトドア'],
    'brand': ['Nike', 'Adidas', 'Regal', 'Nike', 'Timberland'],
    'price': [12000, 11000, 25000, 9000, 28000],
    'color': ['黒', '白', '茶', '青', '茶'],
    'tags': [
        ['軽量', 'クッション', 'メッシュ'],
        ['軽量', '安定性', 'BOOST'],
        ['本革', 'フォーマル', '防水'],
        ['カジュアル', '軽量', 'Air'],
        ['防水', '本革', '厚底'],
    ],
})

# タグをOne-Hotエンコーディング
mlb = MultiLabelBinarizer()
tag_features = pd.DataFrame(
    mlb.fit_transform(products['tags']),
    columns=mlb.classes_,
    index=products.index
)

print("タグ特徴量:")
print(tag_features)

TF-IDF特徴量

商品説明文からTF-IDFベクトルを生成する。

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

# 商品説明文
descriptions = [
    "軽量でクッション性に優れたランニングシューズ。メッシュ素材で通気性抜群。マラソンにも対応。",
    "安定性とクッション性を両立したランニングシューズ。BOOST技術で反発力を提供。",
    "高品質な本革を使用したビジネスシューズ。防水加工で雨の日も安心。フォーマルシーンに最適。",
    "Airクッション搭載の軽量カジュアルスニーカー。普段使いに最適なデザイン。",
    "防水本革のアウトドアブーツ。厚底で悪路でも安定した歩行が可能。冬のアウトドアに。",
]

# TF-IDFベクトル化
tfidf = TfidfVectorizer(max_features=100)
tfidf_matrix = tfidf.fit_transform(descriptions)

# アイテム間類似度
item_similarity = cosine_similarity(tfidf_matrix)
print("TF-IDFベースのアイテム間類似度:")
sim_df = pd.DataFrame(
    item_similarity,
    index=products['name'],
    columns=products['name']
)
print(sim_df.round(3))

Embedding特徴量

より高度な方法として、事前学習済みモデルのEmbeddingを使う。

from sentence_transformers import SentenceTransformer

# 多言語対応のSentence Transformer
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')

# 商品説明文をEmbedding化
embeddings = model.encode(descriptions)
print(f"Embedding次元数: {embeddings.shape[1]}")  # 384次元

# Embeddingベースの類似度
emb_similarity = cosine_similarity(embeddings)
print("Embeddingベースのアイテム間類似度:")
emb_df = pd.DataFrame(
    emb_similarity,
    index=products['name'],
    columns=products['name']
)
print(emb_df.round(3))

類似アイテム検索の実装

特徴量の統合

import numpy as np
from sklearn.preprocessing import StandardScaler, OneHotEncoder

class ContentBasedRecommender:
    """コンテンツベース推薦システム"""

    def __init__(self):
        self.item_vectors = None
        self.item_ids = None

    def build_item_profiles(self, products_df, descriptions):
        """アイテムプロファイルを構築"""
        self.item_ids = products_df['product_id'].values
        features = []

        # 1. カテゴリ特徴量(One-Hot)
        ohe = OneHotEncoder(sparse_output=False)
        cat_features = ohe.fit_transform(
            products_df[['sub_category', 'brand', 'color']]
        )
        features.append(cat_features)

        # 2. 数値特徴量(正規化)
        scaler = StandardScaler()
        num_features = scaler.fit_transform(
            products_df[['price']].values
        )
        features.append(num_features)

        # 3. テキスト特徴量(TF-IDF)
        tfidf = TfidfVectorizer(max_features=50)
        text_features = tfidf.fit_transform(descriptions).toarray()
        features.append(text_features)

        # 4. タグ特徴量(Multi-Hot)
        mlb = MultiLabelBinarizer()
        tag_features = mlb.fit_transform(products_df['tags'])
        features.append(tag_features)

        # 全特徴量を結合
        self.item_vectors = np.hstack(features)
        print(f"アイテムベクトル次元数: {self.item_vectors.shape[1]}")

    def get_similar_items(self, item_id, n=5):
        """指定アイテムに類似したアイテムを返す"""
        idx = np.where(self.item_ids == item_id)[0][0]
        item_vec = self.item_vectors[idx].reshape(1, -1)

        similarities = cosine_similarity(item_vec, self.item_vectors)[0]
        # 自分自身を除外
        similarities[idx] = -1

        top_indices = np.argsort(similarities)[::-1][:n]
        return [
            (self.item_ids[i], similarities[i])
            for i in top_indices
        ]

    def recommend_for_user(self, user_history, n=5):
        """ユーザーの行動履歴に基づいて推薦"""
        # ユーザープロファイル = 購入アイテムのベクトル平均
        history_indices = [
            np.where(self.item_ids == item_id)[0][0]
            for item_id in user_history
        ]
        user_profile = self.item_vectors[history_indices].mean(axis=0).reshape(1, -1)

        # 全アイテムとの類似度
        similarities = cosine_similarity(user_profile, self.item_vectors)[0]

        # 既に購入済みのアイテムを除外
        for idx in history_indices:
            similarities[idx] = -1

        top_indices = np.argsort(similarities)[::-1][:n]
        return [
            (self.item_ids[i], similarities[i])
            for i in top_indices
        ]

H&Mデータセットでの応用

# H&M Personalized Fashion Recommendationsでの活用例
# データ構造:
#   articles.csv: 商品情報(105,542商品)
#     - article_id, product_name, product_type_name
#     - product_group_name, colour_group_name
#     - department_name, section_name, garment_group_name
#     - detail_desc(商品説明文)
#
#   customers.csv: 顧客情報(1,371,980顧客)
#   transactions_train.csv: 取引データ(31,788,324件)

# H&Mデータでの特徴量設計
feature_design = {
    "カテゴリ特徴量": [
        "product_type_name(51種類)",
        "product_group_name(19種類)",
        "colour_group_name(50種類)",
        "department_name(299種類)",
        "section_name(57種類)",
    ],
    "テキスト特徴量": [
        "detail_desc(商品説明文)→ TF-IDF or Embedding",
        "product_name → キーワード抽出",
    ],
    "数値特徴量": [
        "price(価格)",
    ],
    "画像特徴量(発展)": [
        "商品画像 → CNN Embedding",
    ],
}

コンテンツベース推薦の限界と対策

限界:
1. 過度の類似性: ユーザーが見たものと似すぎるものしか出ない
2. 特徴量の質: 良い特徴量設計にはドメイン知識が必要
3. セレンディピティの欠如: 新しいジャンルの発見が起きにくい

対策:
1. 多様性の導入(MMR等)
2. 協調フィルタリングとのハイブリッド
3. Embeddingの活用で暗黙的な特徴も捉える

まとめ

項目ポイント
原理アイテム属性の類似性で推薦
特徴量カテゴリ、テキスト(TF-IDF/Embedding)、タグ
利点Cold Startに強い、ドメイン知識を反映可能
欠点セレンディピティが低い、特徴量設計が必要
応用新商品推薦、「類似商品」セクション

チェックリスト

  • コンテンツベース推薦の原理と利点を説明できる
  • TF-IDFとEmbeddingの違いを理解した
  • 複数の特徴量を統合したアイテムプロファイルを構築できる
  • ユーザープロファイルからの推薦ロジックを理解した
  • H&Mデータセットでの特徴量設計をイメージできる

次のステップへ

コンテンツベース推薦を理解したところで、次はセッション内の直近行動を活用するセッションベース推薦を学ぼう。

推定読了時間: 30分