深入理解矩阵分解:数学原理推导+代码实现+在推荐系统/图像压缩中的应用
矩阵分解:从基础到进阶的全面解析
一、什么是矩阵分解?
矩阵分解(Matrix Factorization)是将一个复杂的矩阵分解为多个简单矩阵乘积的过程。这种技术在机器学习、推荐系统、信号处理等领域有着广泛应用,其核心思想是用低维表示高维数据,发现数据中的潜在结构。
基本形式
给定矩阵 A ∈ R^{m×n},矩阵分解可表示为:
A ≈ B × C
其中 B ∈ R^{m×k},C ∈ R^{k×n},且 k ≪ min(m,n)
二、为什么需要矩阵分解?
- 数据压缩:原始矩阵可能非常大,分解后只需存储小矩阵
- 降维去噪:保留主要特征,过滤噪声
- 发现潜在特征:揭示数据背后的隐含模式
- 解决稀疏性问题:特别适用于稀疏矩阵的补全
三、经典矩阵分解方法
1. 特征值分解(EVD)
适用条件:方阵,且可对角化
A=QΛQ−1 A = QΛQ^{-1} A=QΛQ−1
其中Q是特征向量矩阵,Λ是对角特征值矩阵
import numpy as np
# 特征值分解示例
def eigen_decomposition(A):
eigenvalues, eigenvectors = np.linalg.eig(A)
return eigenvectors, np.diag(eigenvalues), np.linalg.inv(eigenvectors)
# 验证分解
A = np.array([[4, 2], [1, 3]])
Q, Lambda, Q_inv = eigen_decomposition(A)
A_reconstructed = Q @ Lambda @ Q_inv
print("原始矩阵:\n", A)
print("重构矩阵:\n", A_reconstructed)
2. 奇异值分解(SVD)
最通用的分解方法,适用于任意矩阵
A=UΣVT A = UΣV^T A=UΣVT
- U:左奇异向量矩阵,U^T U = I
- Σ:奇异值对角矩阵
- V:右奇异向量矩阵,V^T V = I
截断SVD(Truncated SVD):
保留前k个最大的奇异值,用于降维
A≈UkΣkVkT A ≈ U_k Σ_k V_k^T A≈UkΣkVkT
import numpy as np
from scipy.sparse.linalg import svds
def svd_decomposition(A, k=None):
if k is None:
# 完全SVD
U, s, Vt = np.linalg.svd(A, full_matrices=False)
Sigma = np.diag(s)
else:
# 截断SVD
U, s, Vt = svds(A, k=k)
Sigma = np.diag(s)
return U, Sigma, Vt
# 示例:图像压缩
def compress_image(matrix, k):
U, Sigma, Vt = svd_decomposition(matrix, k)
compressed = U @ Sigma @ Vt
compression_ratio = (U.size + Sigma.size + Vt.size) / matrix.size
return compressed, compression_ratio
3. 非负矩阵分解(NMF)
特点:所有矩阵元素非负,适合文本、图像等非负数据
A≈WHs.t.W≥0,H≥0 A ≈ WH \quad \text{s.t.} \quad W ≥ 0, H ≥ 0 A≈WHs.t.W≥0,H≥0
from sklearn.decomposition import NMF
import numpy as np
def nmf_decomposition(A, n_components):
model = NMF(n_components=n_components, init='random', random_state=42)
W = model.fit_transform(A) # 基矩阵
H = model.components_ # 系数矩阵
# 重构误差
reconstruction_error = model.reconstruction_err_
return W, H, reconstruction_error
# 示例:文档主题提取
doc_term_matrix = np.array([[2, 1, 0, 0],
[0, 1, 3, 2],
[1, 0, 1, 0]])
W, H, error = nmf_decomposition(doc_term_matrix, n_components=2)
print("主题-词矩阵 H:\n", H)
print("文档-主题矩阵 W:\n", W)
4. 矩阵分解在推荐系统中的应用
用户-物品评分矩阵分解:
R≈PQT
R ≈ P Q^T
R≈PQT
其中 R ∈ R^{m×n}(评分矩阵),P ∈ R^{m×k}(用户特征),Q ∈ R^{n×k}(物品特征)
损失函数(加入正则化):
L=∑(i,j)∈Ω(rij−piTqj)2+λ(∣∣P∣∣F2+∣∣Q∣∣F2)
L = \sum_{(i,j)∈Ω}(r_{ij} - p_i^T q_j)^2 + λ(||P||_F^2 + ||Q||_F^2)
L=(i,j)∈Ω∑(rij−piTqj)2+λ(∣∣P∣∣F2+∣∣Q∣∣F2)
class MatrixFactorization:
def __init__(self, n_factors=10, lr=0.01, reg=0.1, n_epochs=100):
self.n_factors = n_factors
self.lr = lr
self.reg = reg
self.n_epochs = n_epochs
def fit(self, R):
n_users, n_items = R.shape
# 初始化用户和物品矩阵
self.P = np.random.normal(scale=1./self.n_factors,
size=(n_users, self.n_factors))
self.Q = np.random.normal(scale=1./self.n_factors,
size=(n_items, self.n_factors))
# 训练过程
for epoch in range(self.n_epochs):
for i in range(n_users):
for j in range(n_items):
if R[i, j] > 0: # 只使用已知评分
error = R[i, j] - np.dot(self.P[i], self.Q[j])
# 梯度更新
self.P[i] += self.lr * (error * self.Q[j] - self.reg * self.P[i])
self.Q[j] += self.lr * (error * self.P[i] - self.reg * self.Q[j])
if epoch % 20 == 0:
loss = self.calculate_loss(R)
print(f"Epoch {epoch}, Loss: {loss:.4f}")
def calculate_loss(self, R):
predictions = np.dot(self.P, self.Q.T)
mask = R > 0
mse = np.mean((predictions[mask] - R[mask]) ** 2)
reg_term = self.reg * (np.sum(self.P**2) + np.sum(self.Q**2))
return mse + reg_term
def predict(self, user_id, item_id):
return np.dot(self.P[user_id], self.Q[item_id])
# 使用示例
R = np.array([[5, 3, 0, 1],
[4, 0, 0, 1],
[1, 1, 0, 5],
[1, 0, 0, 4],
[0, 1, 5, 4]])
mf = MatrixFactorization(n_factors=2, lr=0.001, reg=0.01, n_epochs=200)
mf.fit(R)
print("预测评分:", mf.predict(0, 2))
四、进阶矩阵分解方法
1. 带偏置的矩阵分解
r^ui=μ+bu+bi+puTqi \hat{r}_{ui} = μ + b_u + b_i + p_u^T q_i r^ui=μ+bu+bi+puTqi
- μ:全局平均评分
- b_u:用户偏置
- b_i:物品偏置
2. 概率矩阵分解(PMF)
从概率角度建模,假设评分服从正态分布:
p(R∣P,Q,σ2)=∏i=1N∏j=1M[N(rij∣piTqj,σ2)]Iij
p(R|P,Q,σ^2) = ∏_{i=1}^N ∏_{j=1}^M [N(r_{ij}|p_i^T q_j, σ^2)]^{I_{ij}}
p(R∣P,Q,σ2)=i=1∏Nj=1∏M[N(rij∣piTqj,σ2)]Iij
3. 张量分解
处理多维数据的扩展,如用户-物品-时间三维数据:
X≈Σr=1Rar∘br∘cr
\mathcal{X} ≈ Σ_{r=1}^R a_r ∘ b_r ∘ c_r
X≈Σr=1Rar∘br∘cr
五、矩阵分解的优化算法
- 梯度下降法:最基础的优化方法
- 交替最小二乘法(ALS):固定一个矩阵,优化另一个
- 随机梯度下降(SGD):适合大规模数据
- 坐标下降法:每次优化一个变量
def als_optimize(R, k, steps=10, reg=0.1):
m, n = R.shape
P = np.random.rand(m, k)
Q = np.random.rand(n, k)
for step in range(steps):
# 固定Q,优化P
for i in range(m):
mask = R[i] > 0
if np.sum(mask) > 0:
Q_masked = Q[mask]
R_masked = R[i, mask]
P[i] = np.linalg.solve(
Q_masked.T @ Q_masked + reg * np.eye(k),
Q_masked.T @ R_masked
)
# 固定P,优化Q
for j in range(n):
mask = R[:, j] > 0
if np.sum(mask) > 0:
P_masked = P[mask]
R_masked = R[mask, j]
Q[j] = np.linalg.solve(
P_masked.T @ P_masked + reg * np.eye(k),
P_masked.T @ R_masked
)
return P, Q
六、性能评估指标
def evaluate_predictions(R_true, R_pred, test_indices):
"""评估矩阵分解性能"""
mae = 0
rmse = 0
n = len(test_indices)
for i, j in test_indices:
pred = R_pred[i, j]
true = R_true[i, j]
mae += abs(pred - true)
rmse += (pred - true) ** 2
return mae/n, np.sqrt(rmse/n)
七、实际应用注意事项
- 数据预处理:标准化、归一化
- 冷启动问题:新用户/物品的处理策略
- 隐式反馈:点击、浏览时长等数据的利用
- 实时更新:增量学习策略
- 可扩展性:分布式实现(Spark MLlib)
八、总结
矩阵分解作为数据科学的核心技术,提供了强大的数据降维和特征提取能力。从传统的SVD到现代的深度矩阵分解,其不断发展为解决现实世界问题提供了有力工具。选择哪种分解方法取决于具体问题、数据特性和应用需求。
附名片福利 | 免费技术选型、选题建议、毕设指导、随时答疑~
更多推荐
所有评论(0)