---
id: wiki-2026-0508-item-item-collaborative-filterin
title: Item-Item Collaborative Filtering
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Item-Based CF, Item-Item CF, Item Similarity Recommender]
duplicate_of: none
source_trust_level: A
confidence_score: 0.95
verification_status: applied
tags: [recommender-systems, collaborative-filtering, similarity, embeddings]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
  language: python
  framework: scipy
---

# Item-Item Collaborative Filtering

## 매 한 줄
> **"매 user 매 liked X — 매 X 와 similar Y 의 recommend"**. Item-Item CF (Sarwar et al. 2001, Amazon) 매 item 사이 similarity matrix 의 precompute 매 query time 매 user 의 history 의 weighted sum 의 score 의 produce. 2026 매 baseline / cold-start fallback / explainability 매 still widely deployed alongside neural retrievers.

## 매 핵심

### 매 vs User-User CF
- **User-user**: similar users 의 find — 매 user count >>> item count → expensive.
- **Item-item**: similar items 의 find — 매 item catalog 매 stable, similarity 매 precompute-able.
- 매 Amazon 2003 paper: item-item 매 user-user 의 latency / quality 의 dominate.

### 매 Similarity metrics
- **Cosine**: most common, 매 sparse-friendly.
- **Pearson**: mean-centered cosine, 매 rating-bias 의 remove.
- **Adjusted cosine**: user-mean center 매 implicit feedback 매 useful.
- **Jaccard**: binary interactions (clicked / not).

### 매 Scoring formula
- 매 score(u, i) = Σ_{j ∈ N(i) ∩ I_u} sim(i, j) · r(u, j) / Σ |sim(i, j)|.
- N(i) = top-K similar items, I_u = user u 의 interaction set.

### 매 응용
1. Amazon "customers who bought X also bought Y".
2. Netflix similar-titles row.
3. Spotify radio seed expansion.
4. E-commerce cold-start fallback.

## 💻 패턴

### Pattern 1: Sparse cosine similarity (scipy)
```python
import numpy as np
from scipy.sparse import csr_matrix
from sklearn.preprocessing import normalize

def build_item_sim(interactions: csr_matrix, top_k: int = 50) -> csr_matrix:
    """매 interactions: (n_users, n_items). 매 return: (n_items, n_items) top-k similarity."""
    # Item vectors = columns
    item_norm = normalize(interactions.T, norm="l2", axis=1)  # (n_items, n_users)
    sim = item_norm @ item_norm.T  # (n_items, n_items)
    sim.setdiag(0)  # self-sim 의 zero
    return _keep_topk(sim, top_k)

def _keep_topk(mat: csr_matrix, k: int) -> csr_matrix:
    mat = mat.tolil()
    for i in range(mat.shape[0]):
        row = mat.rows[i]
        data = mat.data[i]
        if len(data) > k:
            idx = np.argsort(data)[-k:]
            mat.rows[i] = [row[j] for j in idx]
            mat.data[i] = [data[j] for j in idx]
    return mat.tocsr()
```

### Pattern 2: Score for a user
```python
def recommend(user_history: dict[int, float], item_sim: csr_matrix, top_n: int = 10):
    """매 user_history: {item_id: rating}. 매 return: top-N (item_id, score)."""
    n_items = item_sim.shape[0]
    scores = np.zeros(n_items)
    sim_sums = np.zeros(n_items)
    for j, r in user_history.items():
        col = item_sim[:, j].toarray().flatten()
        scores += col * r
        sim_sums += np.abs(col)
    sim_sums[sim_sums == 0] = 1
    final = scores / sim_sums
    for j in user_history:
        final[j] = -np.inf  # already-seen 의 mask
    top = np.argpartition(final, -top_n)[-top_n:]
    return [(int(i), float(final[i])) for i in top[np.argsort(final[top])[::-1]]]
```

### Pattern 3: Implicit feedback (BM25-weighted)
```python
def bm25_weight(interactions: csr_matrix, k1: float = 1.2, b: float = 0.75) -> csr_matrix:
    """매 implicit signal (click count) 의 BM25-style weight 의 give — better than raw counts."""
    interactions = interactions.tocsr().astype(float)
    N = interactions.shape[0]
    df = np.bincount(interactions.indices, minlength=interactions.shape[1])
    idf = np.log((N - df + 0.5) / (df + 0.5) + 1)
    doc_len = np.asarray(interactions.sum(axis=1)).flatten()
    avg_dl = doc_len.mean()
    rows, cols = interactions.nonzero()
    tf = interactions.data
    norm = (1 - b) + b * doc_len[rows] / avg_dl
    weighted = tf * (k1 + 1) / (tf + k1 * norm) * idf[cols]
    return csr_matrix((weighted, (rows, cols)), shape=interactions.shape)
```

### Pattern 4: Approximate top-K with Faiss (scale)
```python
import faiss
import numpy as np

def build_item_sim_faiss(item_emb: np.ndarray, top_k: int = 50):
    """매 1M+ items 의 scale — exact dot-product 매 too slow."""
    n, d = item_emb.shape
    item_emb = item_emb / np.linalg.norm(item_emb, axis=1, keepdims=True)
    index = faiss.IndexHNSWFlat(d, 32, faiss.METRIC_INNER_PRODUCT)
    index.add(item_emb.astype(np.float32))
    D, I = index.search(item_emb.astype(np.float32), top_k + 1)
    return I[:, 1:], D[:, 1:]  # drop self
```

### Pattern 5: Hybrid with content embeddings (cold-start)
```python
def hybrid_sim(cf_sim: np.ndarray, content_sim: np.ndarray, alpha: float = 0.7):
    """매 new item 매 CF 매 zero — 매 content_sim 의 fallback."""
    cf_density = (cf_sim != 0).sum(axis=1) / cf_sim.shape[1]
    weight = np.where(cf_density > 0.01, alpha, 0.0)[:, None]
    return weight * cf_sim + (1 - weight) * content_sim
```

### Pattern 6: 2026 modern stack (neural + item-item)
```python
# 매 production 2026: neural retriever (two-tower) + item-item 매 reranker explainability.
def explain_recommendation(target_item, user_history, item_sim):
    """매 'because you liked X, Y, Z' 매 explanation 의 generate."""
    contributions = []
    for j, r in user_history.items():
        s = item_sim[target_item, j]
        contributions.append((j, s * r))
    contributions.sort(key=lambda x: -x[1])
    return contributions[:3]  # top-3 reasons
```

## 매 결정 기준
| 상황 | Approach |
|---|---|
| < 100K items, dense matrix fit | Exact cosine + scipy. |
| 1M+ items | Faiss HNSW approximate. |
| Implicit feedback | BM25 weight + cosine. |
| Cold-start items | Content-hybrid sim. |
| Need explainability | Item-item over neural-only. |
| Massive user history | Combine with two-tower neural. |

**기본값**: BM25-weighted cosine + Faiss HNSW (top-50 neighbors), hybrid with content embedding 매 cold-start.

## 🔗 Graph
- 부모: [[Collaborative-Filtering]] · [[Recommender-Systems]]
- 변형: [[Matrix-Factorization]] · [[ALS]]
- 응용: [[Cold-Start]]
- Adjacent: [[Faiss]] · [[BM25]]

## 🤖 LLM 활용
**언제**: Generating explainable recommendations, baseline implementation, hybrid systems where item-item provides interpretability layer.
**언제 X**: Sequential recommendation (use SASRec / transformer), content-rich domains (use embeddings directly).

## ❌ 안티패턴
- **Dense (n_items × n_items) without top-K**: 1M items → 4TB matrix.
- **Cosine on raw counts**: 매 popularity bias — 매 BM25 / TF-IDF 의 weight.
- **No self-mask in scoring**: recommend already-purchased items.
- **Recompute sim every request**: 매 batch precompute 의 cache.

## 🧪 검증 / 중복
- Verified: Sarwar et al. (2001) "Item-based collaborative filtering", Linden et al. (2003) "Amazon.com recommendations", implicit lib (Frederickson 2024).
- 신뢰도 A.

## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — full content with scipy/Faiss/BM25 patterns and 2026 hybrid stack |
