1.什么是矩阵分解?
矩阵分解就是预测出评分矩阵中的缺失值,然后根据预测值以某种方式向用户推荐。常见的矩阵分解方法有基本矩阵分解(basic MF),正则化矩阵分解)(Regularized MF),基于概率的矩阵分解(PMF)等。
\2. 矩阵分解的思想以及算法步骤?
此处我们只将用户—商品矩阵Rm×nRm×n分解为两个矩阵Pm×kPm×k和Qk×nQk×n,使得满足,
Rm×n≈Pm×k×Qk×n=R^m×n
Rm×n≈Pm×k×Qk×n=R^m×n
从而补全那些缺失值,进而为用户推荐那些可能感兴趣的商品。
我们将使用最小二乘法对那些非缺失的值进行损失评估,即
e2=(rij−r^ij)2=(rij−∑l=1kpil×qlj)2
e2=(rij−r^ij)2=(rij−∑l=1kpil×qlj)2
另外我们使用L2L2正则化,
L2=∑l=1k(p2il+q2lj)
L2=∑l=1k(pil2+qlj2)
其中i∈[1,m],j∈[1,n]i∈[1,m],j∈[1,n], k是我们所指定的大小,因此最终的损失函数为,
loss(pil,qlj)=e2+β2L2 其中pil,qlj即为分解的两个矩阵中的元素,也就是求解参数
loss(pil,qlj)=e2+β2L2 其中pil,qlj即为分解的两个矩阵中的元素,也就是求解参数
接下来我们就可以使用梯度下降算法求解Pm×kPm×k和Qk×nQk×n
∇ploss=∂ loss∂pil=−2(rij−r^ij)qlj+βpil=−2eijqlj+βpil
∇ploss=∂ loss∂pil=−2(rij−r^ij)qlj+βpil=−2eijqlj+βpil
∇qloss=∂ loss∂qlj=−2(rij−r^ij)pil+βqlj=−2eijpil+βqlj
∇qloss=∂ loss∂qlj=−2(rij−r^ij)pil+βqlj=−2eijpil+βqlj
So…,
pil=pil−∇ploss
pil=pil−∇ploss
qlj=qlj−∇qloss
qlj=qlj−∇qloss
这样我们就可以通过迭代(迭代次数,误差容忍度。。。)直到收敛。
\3. 什么是正则化?正则化的作用是什么?
设C是不可约平面代数曲线,S是C的奇点的集合。如果存在紧Riemann面C及全纯映射σ:C→PC^2,使得
(1) σ(C*)=C (2) σ^(-1)(S)是有限点集 (3) σ:C*\σ^(-1)(S)→C\S是一对一的映射
则称(C*,σ)为C的正则化。不至于混淆的时候,也可以称C*为C的正则化。
- 正则化就是对最小化经验误差函数上加约束,这样的约束可以解释为先验知识(正则化参数等价于对参数引入先验分布)。约束有引导作用,在优化误差函数的时候倾向于选择满足约束的梯度减少的方向,使最终的解倾向于符合先验知识(如一般的l-norm先验,表示原问题更可能是比较简单的,这样的优化倾向于产生参数值量级小的解,一般对应于稀疏参数的平滑解)。
- 同时,正则化解决了逆问题的不适定性,产生的解是存在,唯一同时也依赖于数据的,噪声对不适定的影响就弱,解就不会过拟合,而且如果先验(正则化)合适,则解就倾向于是符合真解(更不会过拟合了),即使训练集中彼此间不相关的样本数很少。
\4. 代码实现
from math import *
import numpy
import matplotlib.pyplot as plt
def matrix_factorization(R,P,Q,K,steps=5000,alpha=0.0002,beta=0.02): #矩阵因子分解函数
#steps:梯度下降次数;alpha:步长;beta:β。
Q=Q.T # .T操作表示矩阵的转置
result=[]
for step in range(steps): #梯度下降
for i in range(len(R)):
for j in range(len(R[i])):
eij=R[i][j]-numpy.dot(P[i,:],Q[:,j]) # .DOT表示矩阵相乘
for k in range(K):
if R[i][j]>0: #限制评分大于零
P[i][k]=P[i][k]+alpha*(2*eij*Q[k][j]-beta*P[i][k]) #增加正则化,并对损失函数求导,然后更新变量P
Q[k][j]=Q[k][j]+alpha*(2*eij*P[i][k]-beta*Q[k][j]) #增加正则化,并对损失函数求导,然后更新变量Q
eR=numpy.dot(P,Q)
e=0
for i in range(len(R)):
for j in range(len(R[i])):
if R[i][j]>0:
e=e+pow(R[i][j]-numpy.dot(P[i,:],Q[:,j]),2) #损失函数求和
for k in range(K):
e=e+(beta/2)*(pow(P[i][k],2)+pow(Q[k][j],2)) #加入正则化后的损失函数求和
result.append(e)
if e<0.001: #判断是否收敛,0.001为阈值
break
return P,Q.T,result
if __name__ == '__main__': #主函数
R=[ #原始矩阵,无评分用0代替
[5,3,0,1],
[4,0,0,1],
[1,1,0,5],
[1,0,0,4],
[0,1,5,4]
]
R=numpy.array(R) #创建一个array
N=len(R) #原矩阵R的行数
M=len(R[0]) #原矩阵R的列数
K=3 #K值可根据需求改变
P=numpy.random.rand(N,K) #随机生成一个 N行 K列的矩阵
Q=numpy.random.rand(M,K) #随机生成一个 M行 K列的矩阵
nP,nQ,result=matrix_factorization(R,P,Q,K)
R_MF=numpy.dot(nP,nQ.T)
print(R_MF) #输出新矩阵
#数据可视化(画出图像)
plt.plot(range(len(result)),result)
plt.xlabel("time")
plt.ylabel("loss") #loss :损失函数
plt.show()
运行结果:
[[4.98765298 2.95236783 4.35100489 0.99986468]
[3.97009465 2.32223303 3.5983697 0.99647856]
[1.05398001 0.8612008 5.3682779 4.9637146 ]
[0.97427659 0.89285051 4.5631002 3.97184612]
[1.62385446 1.17360362 4.923405 4.03090791]]
\5.什么是测试集 训练集k折交叉验证
测试集:作用:检验最终选择最优的模型的性能如何
主要是测试训练好的模型的分辨能力(识别率等)
交叉验证往往是对实际应用中数据不充足而采用的,基本目的就是重复使用数据。