1. 引言
k 近邻(KNN)算法原理、矩阵分解及其演变、双线性模型的定义,以及因子分解机(FM)的完整推导与实验表现。推荐系统核心问题------如何利用用户历史行为预测未知偏好------贯穿全文。
2. 个性化推荐与协同过滤
2.1 推荐系统与信息过滤
- 个性化推荐是一种广义信息检索:用户的信息需求是隐含的,没有显式查询。
- 两类方法:
- 基于内容的过滤:推荐与用户过去喜欢的物品具有相似属性(演员、导演、类型等)的物品。
- 协同过滤(Collaborative Filtering):利用其他类似用户的偏好进行推荐。
2.2 评分矩阵与协同过滤目标
数据通常表现为一个稀疏的用户-物品评分矩阵(显式反馈)。协同过滤的核心任务是预测矩阵中的空评分。以电影推荐为例:
- 用户 Boris 看过一些电影,我们需要预测他对《Love Actually》的评分。
- 思路:找到与 Boris 相似的用户(如 Dave、George),取他们对《Love Actually》评分的平均值作为预测。
这引出了两种经典的基于近邻的协同过滤:基于用户(user-based)和基于物品(item-based)。
3. 基于近邻算法的协同过滤
3.1 基于用户的 KNN
- 为每个用户构建画像向量(已知物品的评分)。
- 计算用户间的相似度:
- 余弦相似度 :
sucos(ua,ub)=ua⊤ub∥ua∥∥ub∥ s_u^{cos}(u_a, u_b) = \frac{u_a^\top u_b}{\|u_a\|\|u_b\|} sucos(ua,ub)=∥ua∥∥ub∥ua⊤ub - 皮尔森相关系数 :
sucorr(ua,ub)=∑m(xa,m−xˉa)(xb,m−xˉb)∑m(xa,m−xˉa)2∑m(xb,m−xˉb)2 s_u^{corr}(u_a, u_b) = \frac{\sum_m (x_{a,m} - \bar x_a)(x_{b,m} - \bar x_b)}{\sqrt{\sum_m (x_{a,m} - \bar x_a)^2} \sqrt{\sum_m (x_{b,m} - \bar x_b)^2}} sucorr(ua,ub)=∑m(xa,m−xˉa)2 ∑m(xb,m−xˉb)2 ∑m(xa,m−xˉa)(xb,m−xˉb)
- 余弦相似度 :
- 评分预测公式(基于目标用户的平均评分校正):
x^t,m=xˉt+∑ua∈Nu(ut)su(ut,ua)(xa,m−xˉa)∑ua∈Nu(ut)∣su(ut,ua)∣ \hat x_{t,m} = \bar x_t + \frac{\sum_{u_a \in N_u(u_t)} s_u(u_t, u_a)(x_{a,m} - \bar x_a)}{\sum_{u_a \in N_u(u_t)} |s_u(u_t, u_a)|} x^t,m=xˉt+∑ua∈Nu(ut)∣su(ut,ua)∣∑ua∈Nu(ut)su(ut,ua)(xa,m−xˉa)
3.2 基于物品的 KNN
- 对目标用户未评分的物品 aaa,寻找该用户已评分且与 aaa 最相似的 kkk 个物品。
- 物品相似度衡量同样有余弦相似度、调整余弦相似度和皮尔森相关。
- 预测公式(直接用目标用户已有的评分,无需用户平均校正):
x^t,a=∑ib∈Ni(ut,ia)si(ia,ib)xt,b∑ib∈Ni(ut,ia)∣si(ia,ib)∣ \hat x_{t,a} = \frac{\sum_{i_b \in N_i(u_t, i_a)} s_i(i_a, i_b) x_{t,b}}{\sum_{i_b \in N_i(u_t, i_a)} |s_i(i_a, i_b)|} x^t,a=∑ib∈Ni(ut,ia)∣si(ia,ib)∣∑ib∈Ni(ut,ia)si(ia,ib)xt,b
3.3 实验结论与 KNN 方法局限性
Movielens ML‑100k 数据集(943 用户 × 1682 电影,稀疏度 93.69%)上的实验表明:
- 基于物品的 KNN 通常优于基于用户------物品间的相似度更稳定、更客观。
- 评估指标:MAE、RMSE;随着训练集增大和邻居数 kkk 调整(约 30 最佳),效果提升。
- KNN 方法的局限 :无可学习参数(仅超参数 kkk),效率随数据规模急剧下降,因此需要参数化、可学习的模型。
python
import numpy as np
import pandas as pd
from sklearn.metrics.pairwise import cosine_similarity
# 1. 加载数据:使用 MovieLens 100k 的 u.data 文件
columns = ['user_id', 'item_id', 'rating', 'timestamp']
ratings = pd.read_csv('u.data', sep='\t', names=columns)
# 构建用户-物品评分矩阵,缺失值填 0
rating_matrix = ratings.pivot_table(index='user_id',
columns='item_id',
values='rating').fillna(0)
# 2. 计算用户间的余弦相似度
user_similarity = cosine_similarity(rating_matrix)
user_ids = rating_matrix.index # 用户 ID 列表
# 3. 基于 KNN 的评分预测函数
def predict_rating(user_id, item_id, k=30):
"""
基于用户相似度的 KNN 协同过滤预测评分。
user_id: 目标用户 ID(从 1 开始)
item_id: 目标物品 ID(从 1 开始)
k: 最近邻用户数量
"""
# 如果目标物品已有评分,直接返回
if rating_matrix.loc[user_id, item_id] > 0:
return rating_matrix.loc[user_id, item_id]
# 获取目标用户在相似度矩阵中的位置索引
user_idx = user_ids.get_loc(user_id)
sim_scores = user_similarity[user_idx]
# 找到相似度最高的 k 个用户(排除自身)
nearest_indices = np.argsort(sim_scores)[::-1][1:k+1]
# 收集邻居评分并加权平均
ratings_sum = 0.0
sim_sum = 0.0
for idx in nearest_indices:
neighbor_id = user_ids[idx]
r = rating_matrix.loc[neighbor_id, item_id]
if r > 0: # 只考虑有过评分的邻居
ratings_sum += sim_scores[idx] * r
sim_sum += np.abs(sim_scores[idx])
if sim_sum == 0:
return 0 # 若无邻居评分,返回 0 或全局平均分
return ratings_sum / sim_sum
# 示例:预测用户1对物品10的评分
pred = predict_rating(user_id=1, item_id=10, k=30)
print(f"预测评分: {pred:.2f}")
4. k 近邻算法(KNN)本身
4.1 经典 KNN
- 非参数方法,可用于分类和回归。
- 对于输入 xxx,在特征空间中找到 kkk 个最近邻 Nk(x)N_k(x)Nk(x):
- 回归 :y^(x)=1k∑xi∈Nk(x)yi\hat y(x) = \frac{1}{k} \sum_{x_i \in N_k(x)} y_iy^(x)=k1∑xi∈Nk(x)yi
- 分类:多数投票。
4.2 广义 KNN 与超参数
引入相似度函数 s(x,xi)s(x, x_i)s(x,xi) 后:
y^(x)=∑xi∈Nk(x)s(x,xi)yi∑xi∈Nk(x)s(x,xi) \hat y(x) = \frac{\sum_{x_i \in N_k(x)} s(x, x_i) y_i}{\sum_{x_i \in N_k(x)} s(x, x_i)} y^(x)=∑xi∈Nk(x)s(x,xi)∑xi∈Nk(x)s(x,xi)yi
- 实际上有 NNN 个参数(每个实例即一个参数),有效参数约 N/kN/kN/k。
- 超参数 kkk 必须在验证集上选择,k=1k=1k=1 虽然训练误差为 0,但泛化极差。
5. 矩阵分解------双线性模型的基础
5.1 基本矩阵分解模型
将评分矩阵 RRR 近似为两个低秩矩阵的乘积:
r^u,i=pu⊤qi \hat r_{u,i} = p_u^\top q_i r^u,i=pu⊤qi
- pup_upu、qiq_iqi 分别是用户和物品的隐因子向量。
- 损失函数(加入 L2 正则):
L=∑(u,i)∈D12(ru,i−pu⊤qi)2+λ2(∥pu∥2+∥qi∥2) \mathcal{L} = \sum_{(u,i) \in D} \frac{1}{2}(r_{u,i} - p_u^\top q_i)^2 + \frac{\lambda}{2}(\|p_u\|^2 + \|q_i\|^2) L=(u,i)∈D∑21(ru,i−pu⊤qi)2+2λ(∥pu∥2+∥qi∥2) - 梯度下降更新参数。
5.2 带偏置的矩阵分解
预测值加入全局偏置、用户偏置和物品偏置:
r^u,i=μ+bu+bi+pu⊤qi \hat r_{u,i} = \mu + b_u + b_i + p_u^\top q_i r^u,i=μ+bu+bi+pu⊤qi
这种方法显著提高了预测精度。
5.3 时间动态与 SVD++
评分行为本身随时间演变(用户口味变化、物品热度变化等)。带时间的模型:
ru,i(t)=μ+bu(t)+bi(t)+pu(t)⊤qi r_{u,i}(t) = \mu + b_u(t) + b_i(t) + p_u(t)^\top q_i ru,i(t)=μ+bu(t)+bi(t)+pu(t)⊤qi
SVD++ 进一步结合邻居信息,为每个物品引入两个向量(表示自身的 qiq_iqi 和用于度量相似度的 yiy_iyi):
r^u,i=bu,i+qi⊤(pu+∣N(u)∣−12∑j∈N(u)yj) \hat r_{u,i} = b_{u,i} + q_i^\top \left( p_u + |N(u)|^{-\frac{1}{2}} \sum_{j \in N(u)} y_j \right) r^u,i=bu,i+qi⊤ pu+∣N(u)∣−21j∈N(u)∑yj
在 Netflix 奖比赛中,矩阵分解和 KNN 的变体都取得了优异表现。
6. 双线性模型与因子分解机
6.1 双线性(Bilinear)的含义
二元函数 f:Rn×Rm→Rlf: \mathbb{R}^n \times \mathbb{R}^m \to \mathbb{R}^lf:Rn×Rm→Rl 是双线性的,当固定某一侧向量时,它对另一侧是线性的。向量内积是最简单的双线性函数,因此:
矩阵分解模型 r^=pu⊤qi\hat r = p_u^\top q_ir^=pu⊤qi 正是一种双线性模型。
6.2 基于特征的矩阵分解(因子分解机,FM)
将推荐问题中所有信息(用户 id、物品 id、时间、类别等)统一视为特征,并学习特征间的两两交互:
y^(x)=w0+∑i=1dwixi+∑i=1d−1∑j=i+1d⟨vi,vj⟩xixj \hat y(\mathbf{x}) = w_0 + \sum_{i=1}^d w_i x_i + \sum_{i=1}^{d-1} \sum_{j=i+1}^d \langle v_i, v_j \rangle x_i x_j y^(x)=w0+i=1∑dwixi+i=1∑d−1j=i+1∑d⟨vi,vj⟩xixj
- 每个特征(包括每个类别特征的独热编码)学习一个隐向量 viv_ivi。
- 基于向量内积的双线性交互项使模型能够拟合稀疏特征间的关联。
6.3 计算效率优化
原始二次交互复杂度为 O(kd2)O(kd^2)O(kd2),利用恒等式可降到 O(kd)O(kd)O(kd):
∑i=1d−1∑j=i+1d⟨vi,vj⟩xixj=12∑f=1k((∑i=1dvi,fxi)2−∑i=1dvi,f2xi2) \sum_{i=1}^{d-1} \sum_{j=i+1}^d \langle v_i, v_j \rangle x_i x_j = \frac{1}{2} \sum_{f=1}^k \left( \left(\sum_{i=1}^d v_{i,f} x_i \right)^2 - \sum_{i=1}^d v_{i,f}^2 x_i^2 \right) i=1∑d−1j=i+1∑d⟨vi,vj⟩xixj=21f=1∑k (i=1∑dvi,fxi)2−i=1∑dvi,f2xi2
这使得 FM 在大规模稀疏数据上高效实用。
6.4 实验结果与对比
在 Criteo 和 iPinYou 数据集上,线性模型(Logistic Regression)、双线性模型(FM)与非线性模型(Deep Neural Networks)的 AUC/Log Loss 对比显示:
- FM 作为双线性模型,比完全线性的 LR 有显著提升;
- 深度模型虽性能更强,但 FM 在可解释性、效率和标准化的便捷性上仍有明显优势。
7. 总结
- 协同过滤的核心是学习数据点(用户/物品)之间的相似性,并据此进行预测。
- KNN 是最简单的非参数化协同过滤方法,解释性强但缺乏参数学习和可扩展性。
- 矩阵分解通过隐因子内积将评分矩阵参数化,是最基础的双线性模型;加入偏置、时间动态和邻居信息后,性能大幅提升。
- 双线性模型指固定一侧变元时对另一侧呈线性变换的映射,向量内积是其典型操作------对一边参数求梯度正好得到另一边的参数。
- 因子分解机(FM) 将矩阵分解推广为通用特征交互学习器,在推荐系统和点击率预估中兼具效率与表达能力,是双线性模型向全特征空间拓展的代表。
从 KNN 到矩阵分解再到 FM,体现了从非参数邻居相似性到参数化双线性交互的演进路径,也为理解后续深度推荐模型奠定了理论基础。