基于矩阵分解的推荐算法
1、概述
基于用户和基于项的协同过滤推荐算法,难以实现大数据量下的实时推荐。这时我们可以使用基于模型的协同过滤算法,矩阵分解(Matrix Factorization,MF)就是其中一种。
矩阵分解:将一个矩阵分解为两个或多个矩阵的乘积。mxn—>mxk X kxn
非负矩阵分解:一般的矩阵分解,分解的矩阵有正有负。很多实际应用中,负数没有意义,如文本等等。NMF中要求原矩阵和分解后矩阵都为非负矩阵,这个分解存在唯一。
基于模型的协同过滤算法:(1)建立模型;(2)利用训练好的模型进行推荐。
基于矩阵分解的推荐算法:(1)对用户商品矩阵分解;(2)利用分解后的矩阵预测原始矩阵中的未打分项。
2、基于矩阵分解的推荐算法
损失函数:将原始评分矩阵Rmxn分解后得到两个矩阵的乘积,这两个矩阵的乘积构建了新的评分矩阵,将非“-”元素,在原始和新的之间的误差的平方作为损失,我们需要求解所有非“-”项的损失之和的最小值。通常会加入正则化项。
损失函数求解:可使用梯度下降方法,求损失函数的负梯度,根据负梯度的方向更新变量(也就是分解后的各个矩阵的对应位置的元素)。目的是求得分解后的矩阵。
预测:得到分解的矩阵后,模型便建立好了。要为指定的用户i推荐其未打分的项,若要计算用户i对商品j的打分,k为分解矩阵的维度,。求得多个商品的打分后,进行降序排序。
3、利用矩阵分解进行推荐
首先导入数据并矩阵化;
然后利用梯度下降对矩阵分解得到模型(需要设置分解矩阵的维度k,学习率alpha,正则化参数beta,最大迭代次数maxCycles),输出分解后的矩阵p和q。
预测时,利用得到的分解矩阵p和q和前面的公式,可得到某用户user所有未打分商品的打分,然后排序输出。
# coding:UTF-8
import numpy as np
def load_data(path): #导入数据
f = open(path)
data = []
for line in f.readlines():
arr = []
lines = line.strip().split("\t")
for x in lines:
if x != "-":
arr.append(float(x))
else:
arr.append(float(0))
data.append(arr)
f.close()
return np.mat(data)
def gradAscent(dataMat, k, alpha, beta, maxCycles):#利用梯度下降法对矩阵进行分解
m, n = np.shape(dataMat)
# 1、初始化p和q
p = np.mat(np.random.random((m, k)))
q = np.mat(np.random.random((k, n)))
for step in range(maxCycles):
for i in range(m):
for j in range(n):
if dataMat[i, j] > 0:
error = dataMat[i, j]
for r in range(k):
error = error - p[i, r] * q[r, j]
for r in range(k):
p[i, r] = p[i, r] + alpha * (2 * error * q[r, j] - beta * p[i, r])
q[r, j] = q[r, j] + alpha * (2 * error * p[i, r] - beta * q[r, j])
loss = 0.0
for i in range(m):
for j in range(n):
if dataMat[i, j] > 0:
error = 0.0
for r in range(k):
error = error + p[i, r] * q[r, j]
loss = (dataMat[i, j] - error) * (dataMat[i, j] - error)
for r in range(k):
loss = loss + beta * (p[i, r] * p[i, r] + q[r, j] * q[r, j]) / 2
if loss < 0.001:
break
if step % 1000 == 0:
print("\titer: ", step, " loss: ", loss)
return p, q
def save_file(file_name, source):#保存结果
f = open(file_name, "w")
m, n = np.shape(source)
for i in range(m):
tmp = []
for j in range(n):
tmp.append(str(source[i, j]))
f.write("\t".join(tmp) + "\n")
f.close()
def prediction(dataMatrix, p, q, user):#为用户user未互动的项打分
n = np.shape(dataMatrix)[1]
predict = {}
for j in range(n):
if dataMatrix[user, j] == 0:
predict[j] = (p[user,] * q[:, j])[0, 0]
return sorted(predict.items(), key=lambda d: d[1], reverse=True)
def top_k(predict, k):#为用户推荐前k个商品
top_recom = []
len_result = len(predict)
if k >= len_result:
top_recom = predict
else:
for i in range(k):
top_recom.append(predict[i])
return top_recom
if __name__ == "__main__":
# 1、导入用户商品矩阵
print("----------- 1、load data -----------")
dataMatrix = load_data("data.txt")
# 2、利用梯度下降法对矩阵进行分解
print("----------- 2、training -----------")
p, q = gradAscent(dataMatrix, 5, 0.0002, 0.02, 5000)
# 3、保存分解后的结果
print("----------- 3、save decompose -----------")
save_file("p", p)
save_file("q", q)
# 4、预测
print("----------- 4、prediction -----------")
predict = prediction(dataMatrix, p, q, 0)
# 进行Top-K推荐
print("----------- 5、top_k recommendation ------------")
top_recom = top_k(predict, 2)
print(top_recom)
print(p * q)