大数据——协同过滤推荐算法:矩阵分解

矩阵分解的方法也分为很多种:SVD、LFM、BiasSVD和SVD++。

  • Traditional SVD
    一般SVD矩阵分解指的是SVD奇异值分解,将矩阵分解成三个相乘矩阵,中间矩阵就是奇异值矩阵。SVD分解的前提是矩阵是稠密的,现实场景中数据都是稀疏的,无法使用SVD,需要均值或者其他方法来填充,会对数据造成一定影响。具体公式如下:
    M m × n = U m × k ∑ k × k K k × n T M_{m×n} = U_{m×k}\sum_{k×k}K^T_{k×n} Mm×n=Um×kk×kKk×nT
  • FunkSVD(LFM)
    FunkSVD是最原始的LFM模型,它将矩阵分解为2个矩阵:用户-隐含特征矩阵,物品-隐含特征矩阵,一般这个过程跟线性回归类似。以下公式为矩阵分解后的损失函数,p为用户-隐含特征矩阵,q为物品-隐含特征矩阵,我们通过求损失函数的最小值来计算p和q,后面部分为L2范式,防止过拟合。下面公式用随机梯度下降来求最优解。
    m i n q p ∑ ( u , i ) ∈ R ( r u i − q i T p u ) 2 + λ ( ∣ ∣ q i ∣ ∣ 2 + ∣ ∣ p u ∣ ∣ 2 ) \mathop{min}\limits_{qp}\sum_{(u,i)∈R}(r_{ui}-q^T_ip_u)^2+\lambda(||q_i||^2+||p_u||^2) qpmin(u,i)R(ruiqiTpu)2+λ(∣∣qi2+∣∣pu2)
  • BiasSVD
    BiasSVD就是在FunkSVD的基础上加上Baseline基准预测的偏置项,具体公式如下:
    m i n q p ∑ ( u , i ) ∈ R ( r u i − u − b u − b i − q i T p u ) 2 + λ ( ∣ ∣ q i ∣ ∣ 2 + ∣ ∣ p u ∣ ∣ 2 + ∣ ∣ b u ∣ ∣ 2 + ∣ ∣ b i ∣ ∣ 2 ) \mathop{min}\limits_{qp}\sum_{(u,i)∈R}(r_{ui}-u-b_u-b_i-q^T_ip_u)^2+\lambda(||q_i||^2+||p_u||^2+||b_u||^2+||b_i||^2) qpmin(u,i)R(ruiububiqiTpu)2+λ(∣∣qi2+∣∣pu2+∣∣bu2+∣∣bi2)
  • SVD++
    改进的BiasSVD,即在BiasSVD的基础上再加上用户的隐式反馈信息。这里不做多介绍。

1 LFM原理解析

LFM隐语义模型的核心思想是通过隐含特征联系用户和物品。
在这里插入图片描述

P是用户和隐含特征矩阵,这里表示三个隐含特征;
Q是隐含特征和物品矩阵
Q是User-Item,由P*Q得来。

我们利用矩阵分解技术,将User-Item评分矩阵分解为P和Q的矩阵,然后利用P*Q还原评分矩阵。其中 R 11 = P 1 , k ⃗ ⋅ Q k , 1 ⃗ R_{11} = \vec{P_{1,k}}·\vec{Q_{k,1}} R11=P1,k Qk,1
所以我们的评分为:
r u i ^ = p u , k ⃗ ⋅ q i , k ⃗ = ∑ k = 1 k p u k q i k \hat{r_{ui}} = \vec{p_{u,k}}·\vec{q_{i,k}} = \sum_{k=1}^{k}p_{uk}q_{ik} rui^=pu,k qi,k =k=1kpukqik

损失函数

C o s t = ∑ u , i ∈ R ( r u i − r ^ u i ) 2 = ∑ u , i ∈ R ( r u i − ∑ k = 1 k p u k q i k ) 2 Cost = \sum_{u,i∈R}(r_{ui}-\hat r_{ui})^2 = \sum_{u,i∈R}(r_{ui}-\sum_{k=1}^{k}p_{uk}q_{ik})^2 Cost=u,iR(ruir^ui)2=u,iR(ruik=1kpukqik)2
加入L2范式防止过拟合,如下:
C o s t = ∑ u , i ∈ R ( r u i − ∑ k = 1 k p u k q i k ) 2 + λ ( ∑ U p u k 2 + ∑ I q i k 2 ) Cost = \sum_{u,i∈R}(r_{ui}-\sum_{k=1}^{k}p_{uk}q_{ik})^2 +\lambda(\sum_U p^2_{uk}+\sum_I q^2_{ik}) Cost=u,iR(ruik=1kpukqik)2+λ(Upuk2+Iqik2)
对损失函数求偏导可得:
∂ ∂ p u k C o s t = 2 ∑ u , i ∈ R ( r u i − ∑ k = 1 k p u k q i k ) ( − q i k ) + 2 λ p u k \frac{∂}{∂p_{uk}}Cost = 2\sum_{u,i∈R}(r_{ui}-\sum_{k=1}^{k}p_{uk}q_{ik})(-q_{ik}) + 2\lambda p_{uk} pukCost=2u,iR(ruik=1kpukqik)(qik)+2λpuk
∂ ∂ q i k C o s t = 2 ∑ u , i ∈ R ( r u i − ∑ k = 1 k p u k q i k ) ( − p u k ) + 2 λ q i k \frac{∂}{∂q_{ik}}Cost = 2\sum_{u,i∈R}(r_{ui}-\sum_{k=1}^{k}p_{uk}q_{ik})(-p_{uk}) + 2\lambda q_{ik} qikCost=2u,iR(ruik=1kpukqik)(puk)+2λqik

随机梯度下降法优化

根据偏导可更新梯度下降参数:
p u k : = p u k + α [ ∑ u , i ∈ R ( r u i − ∑ k = 1 k p u k q i k ) ( q i k ) − λ 1 p u k ] p_{uk}:=p_{uk} + \alpha[\sum_{u,i∈R}(r_{ui}-\sum_{k=1}^{k}p_{uk}q_{ik})(q_{ik}) - \lambda_1 p_{uk}] puk:=puk+α[u,iR(ruik=1kpukqik)(qik)λ1puk]
q i k : = p i k + α [ ∑ u , i ∈ R ( r u i − ∑ k = 1 k p u k q i k ) ( p u k ) − λ 2 q i k ] q_{ik}:=p_{ik} + \alpha[\sum_{u,i∈R}(r_{ui}-\sum_{k=1}^{k}p_{uk}q_{ik})(p_{uk}) -\lambda_2 q_{ik}] qik:=pik+α[u,iR(ruik=1kpukqik)(puk)λ2qik]
随机梯度下降
应用到每个向量里
p u k : = p u k + α [ ( r u i − ∑ k = 1 k p u k q i k ) ( q i k ) − λ 1 p u k ] p_{uk}:=p_{uk} + \alpha[(r_{ui}-\sum_{k=1}^{k}p_{uk}q_{ik})(q_{ik}) - \lambda_1 p_{uk}] puk:=puk+α[(ruik=1kpukqik)(qik)λ1puk]
q i k : = p i k + α [ ( r u i − ∑ k = 1 k p u k q i k ) ( p u k ) − λ 2 q i k ] q_{ik}:=p_{ik} + \alpha[(r_{ui}-\sum_{k=1}^{k}p_{uk}q_{ik})(p_{uk}) -\lambda_2 q_{ik}] qik:=pik+α[(ruik=1kpukqik)(puk)λ2qik]

算法实现

这里只展示LFM算法的代码,数据集分割代码和评估代码见:大数据——协同过滤推荐算法:线性回归算法

# FunkSVD
class LFM(object):'''max_epochs 梯度下降迭代次数alpha 学习率reg 过拟合参数columns 数据字段名称'''def __init__(self,max_epochs,p_reg,q_reg,alpha,number_LatentFactors=30,columns=['userId','movieId','rating']):self.max_epochs = max_epochsself.p_reg = p_regself.q_reg = q_regself.number_LatentFactors=number_LatentFactors #隐式特征的数量self.alpha = alphaself.columns = columnsdef fit(self,data):''':param data:uid,mid,rating:return:'''self.data = data# 用户评分数据self.users_rating = data.groupby(self.columns[0]).agg([list])[[self.columns[1], self.columns[2]]]# 电影评分数据self.items_rating = data.groupby(self.columns[1]).agg([list])[[self.columns[0], self.columns[2]]]# 全局平均分self.global_mean = self.data[self.columns[2]].mean()# 调用随机梯度下降训练模型参数self.p,self.q = self.sgd()def _init_matrix(self):# 构建p的矩阵,其中第二项元素的大小为用户数量*隐式特征p = dict(zip(self.users_rating.index, np.random.rand(len(self.users_rating), self.number_LatentFactors).astype(np.float32)))# 构建q的矩阵,其中第二项元素的大小为物品数量*隐式特征q = dict(zip(self.items_rating.index,np.random.rand(len(self.items_rating), self.number_LatentFactors).astype(np.float32)))return p,qdef sgd(self):'''最小二乘法,优化q和p值:return: q p'''p,q = self._init_matrix()for i in range(self.max_epochs):error_list = []for uid,mid,r_ui in self.data.itertuples(index=False):# user-lf p# item-lf qv_pu = p[uid]v_qi = q[mid]err = np.float32(r_ui - np.dot(v_pu, v_qi))v_pu += self.alpha*(err*v_qi - self.p_reg*v_pu)v_qi += self.alpha*(err*v_pu - self.q_reg*v_qi)p[uid] = v_puq[mid] = v_qierror_list.append(err**2)return p,qdef predict(self,uid,mid):'''使用评分公式进行预测param uid,mid;return predict_rating;'''if uid not in self.users_rating.index or mid not in self.items_rating.index:return self.global_meanp_u = self.p[uid]q_i = self.q[mid]return np.dot(p_u,q_i)def test(self,testset):'''使用预测函数预测测试集数据param testset;return yield;'''for uid,mid,real_rating in testset.itertuples(index=False):try:# 使用predict函数进行预测pred_rating = self.predict(uid,mid)except Exception as e:print(e)else:# 返回生成器对象yield uid,mid,real_rating,pred_rating

测试LFM算法

trainset, testset = data_split('ml-latest-small/ratings.csv',random=True)
lfm = LFM(100,0.01,0.01,0.02,10,['userId','movieId','rating'])
lfm.fit(trainset)
pred_test = lfm.test(testset)
# 生成器对象用list进行转化,然后转化为dataframe格式
df_pred_LFM = pd.DataFrame(list(pred_test), columns=[['userId','movieId','rating','pred_rating']])
rmse, mae = accuray(df_pred_als,'all')
print('rmse:',rmse,';mae:',mae)

rmse: 1.0718 ;mae: 0.8067

2 BiasSVD原理

BiasSVD是在FunkSVD矩阵分解的基础上加上了偏置项的。评分公式如下:
r ^ u i = u + b u + b i + p u k ⃗ ⋅ q k i ⃗ = u + b u + b i + ∑ k = 1 k p u k ⋅ q k i \hat r_{ui} = u+b_u+b_i+\vec{p_{uk}}·\vec{q_{ki}} = u+b_u+b_i+\sum^{k}_{k=1}{p_{uk}}·{q_{ki}} r^ui=u+bu+bi+puk qki =u+bu+bi+k=1kpukqki

损失函数
C o s t = ∑ u , i ∈ R ( r u i − r ^ u i ) 2 = ∑ u , i ∈ R ( r u i − u − b u − b i − ∑ k = 1 k p u k ⋅ q k i ) 2 Cost = \sum_{u,i∈R}(r_{ui}-\hat r_{ui})^2 = \sum_{u,i∈R}(r_{ui}-u-b_u-b_i-\sum^{k}_{k=1}{p_{uk}}·{q_{ki}})^2 Cost=u,iR(ruir^ui)2=u,iR(ruiububik=1kpukqki)2
加入L2范式
C o s t = ∑ u , i ∈ R ( r u i − r ^ u i ) 2 = ∑ u , i ∈ R ( r u i − u − b u − b i − ∑ k = 1 k p u k ⋅ q k i ) 2 + λ ( ∑ U b u 2 + ∑ I b i 2 + ∑ U p u k 2 + ∑ I q i k 2 ) Cost = \sum_{u,i∈R}(r_{ui}-\hat r_{ui})^2 = \sum_{u,i∈R}(r_{ui}-u-b_u-b_i-\sum^{k}_{k=1}{p_{uk}}·{q_{ki}})^2 +\lambda(\sum_Ub^2_u+\sum_Ib^2_i+\sum_Up^2_{uk}+\sum_Iq^2_{ik}) Cost=u,iR(ruir^ui)2=u,iR(ruiububik=1kpukqki)2+λ(Ubu2+Ibi2+Upuk2+Iqik2)

随机梯度下降法优化
梯度下降更新参数:
p u k : = p u k + α [ ( r u i − u − b u − b i − ∑ k = 1 k p u k ⋅ q k i ) q i k − λ 1 p u k ] p_{uk}:=p_{uk} + \alpha[(r_{ui}-u-b_u-b_i-\sum^{k}_{k=1}{p_{uk}}·{q_{ki}})q_{ik}-\lambda_1p_{uk}] puk:=puk+α[(ruiububik=1kpukqki)qikλ1puk]
q i k : = p i k + α [ ( r u i − u − b u − b i − ∑ k = 1 k p u k ⋅ q k i ) p u k − λ 2 q i k ] q_{ik}:=p_{ik} + \alpha[(r_{ui}-u-b_u-b_i-\sum^{k}_{k=1}{p_{uk}}·{q_{ki}})p_{uk}-\lambda_2q_{ik}] qik:=pik+α[(ruiububik=1kpukqki)pukλ2qik]
b u : = b u + α [ ( r u i − u − b u − b i − ∑ k = 1 k p u k ⋅ q k i ) − λ 3 b u ] b_{u}:=b_{u} + \alpha[(r_{ui}-u-b_u-b_i-\sum^{k}_{k=1}{p_{uk}}·{q_{ki}})-\lambda_3b_{u}] bu:=bu+α[(ruiububik=1kpukqki)λ3bu]
b i : = b i + α [ ( r u i − u − b u − b i − ∑ k = 1 k p u k ⋅ q k i ) − λ 4 b i ] b_{i}:=b_{i} + \alpha[(r_{ui}-u-b_u-b_i-\sum^{k}_{k=1}{p_{uk}}·{q_{ki}})-\lambda_4b_{i}] bi:=bi+α[(ruiububik=1kpukqki)λ4bi]

算法实现

# BiasSVD
class BiasSvd(object):'''max_epochs 梯度下降迭代次数alpha 学习率reg 过拟合参数columns 数据字段名称'''def __init__(self,alpha,p_reg,q_reg,bu_reg,bi_reg,number_LatentFactors=10,max_epochs=10,columns=['userId','movieId','rating']):self.max_epochs = max_epochsself.p_reg = p_regself.q_reg = q_regself.bu_reg = bu_regself.bi_reg = bi_regself.number_LatentFactors=number_LatentFactors #隐式特征的数量self.alpha = alphaself.columns = columnsdef fit(self,data):''':param data:uid,mid,rating:return:'''self.data = data# 用户评分数据self.users_rating = data.groupby(self.columns[0]).agg([list])[[self.columns[1], self.columns[2]]]# 电影评分数据self.items_rating = data.groupby(self.columns[1]).agg([list])[[self.columns[0], self.columns[2]]]# 全局平均分self.global_mean = self.data[self.columns[2]].mean()# 调用随机梯度下降训练模型参数self.p,self.q, self.bu,self.bi= self.sgd()def _init_matrix(self):# 构建p的矩阵,其中第二项元素的大小为用户数量*隐式特征p = dict(zip(self.users_rating.index, np.random.rand(len(self.users_rating), self.number_LatentFactors).astype(np.float32)))# 构建q的矩阵,其中第二项元素的大小为物品数量*隐式特征q = dict(zip(self.items_rating.index,np.random.rand(len(self.items_rating), self.number_LatentFactors).astype(np.float32)))return p,qdef sgd(self):'''随机梯度下降,优化q和p值:return: q p'''p,q = self._init_matrix()bu = dict(zip(self.users_rating.index, np.zeros(len(self.users_rating))))bi = dict(zip(self.items_rating.index,np.zeros(len(self.items_rating))))for i in range(self.max_epochs):error_list = []for uid,mid,r_ui in self.data.itertuples(index=False):# user-lf p# item-lf qv_pu = p[uid]v_qi = q[mid]err = np.float32(r_ui - self.global_mean - bu[uid] - bi[mid]-np.dot(v_pu, v_qi))v_pu += self.alpha*(err*v_qi - self.p_reg*v_pu)v_qi += self.alpha*(err*v_pu - self.q_reg*v_qi)p[uid] = v_puq[mid] = v_qibu[uid] += self.alpha*(err - self.bu_reg*bu[uid])bi[mid] += self.alpha*(err - self.bi_reg*bi[mid])error_list.append(err**2)return p,q,bu,bidef predict(self,uid,mid):'''使用评分公式进行预测param uid,mid;return predict_rating;'''if uid not in self.users_rating.index or mid not in self.items_rating.index:return self.global_meanp_u = self.p[uid]q_i = self.q[mid]return self.global_mean+self.bu[uid]+self.bi[mid]+np.dot(p_u,q_i)def test(self,testset):'''使用预测函数预测测试集数据param testset;return yield;'''for uid,mid,real_rating in testset.itertuples(index=False):try:# 使用predict函数进行预测pred_rating = self.predict(uid,mid)except Exception as e:print(e)else:# 返回生成器对象yield uid,mid,real_rating,pred_rating

算法使用

trainset, testset = data_split('ml-latest-small/ratings.csv',random=True)
bsvd = BiasSvd(0.02,0.01,0.01,0.01,0.01,10,20,['userId','movieId','rating'])
bsvd.fit(trainset)
pred_test = bsvd.test(testset)
# 生成器对象用list进行转化,然后转化为dataframe格式
df_pred_LFM = pd.DataFrame(list(pred_test), columns=[['userId','movieId','rating','pred_rating']])
rmse, mae = accuray(df_pred_als,'all')
print('rmse:',rmse,';mae:',mae)

rmse: 1.0718 ;mae: 0.8067

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/67313.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

16.3.2 【Linux】程序的管理

程序之间是可以互相控制的。举例来说,你可以关闭、重新启动服务器软件,服务器软件本身是个程序, 你既然可以让她关闭或启动,当然就是可以控制该程序。 使用kill-l或者是man 7 signal可以查询到有多少个signal。主要的讯号代号与名…

【Uni-App】uview 开发多端应用,密码显示隐藏功能不生效问题

出现的问题: 使用uview组件u-input框密码绑定时会出现右侧密码显隐图标不显示的问题 思路: 1.看了下uview源码,发现这有一段注释,我们需要把源码修改一下,问题出在这里 这行代码修改为 :password"password || …

等保案例 1

用户简介 吉林省人力资源和社会保障厅(简称“吉林省人社厅”)响应《网络安全法》的建设要求,为了向吉林省人民提供更好、更快、更稳定的信息化服务,根据《网络安全法》和等级保护2.0相关标准,落实网络安全与信息化建设…

C++异常

目录 一、C语言处理错误的常用方式二、C异常的概念三、异常的使用3.1 异常的抛出和捕获3.2 异常的重新抛出3.3 异常安全3.4 异常规范 四、自定义异常体系五、C标准库的异常体系六、异常的优缺点(重点) 一、C语言处理错误的常用方式 传统的错误处理机制&…

机器人CPP编程基础-01第一个程序Hello World

很多课程先讲C/C或者一些其他编程课,称之为基础课程。然后到本科高年级进行机器人专业课学习,这样时间损失非常大,效率非常低。 C/单片机/嵌入式/ROS等这些编程基础可以合并到一门课中进行实现,这些素材已经迭代三轮以上&#xf…

Python Opencv实践 - 图像旋转

import cv2 as cv import numpy as np import matplotlib.pyplot as pltimg cv.imread("../SampleImages/pomeranian.png", cv.IMREAD_COLOR)#图像旋转 #Opencv中的旋转,首先通过cv.getRotationMatrix2D获得旋转矩阵 #cv.getRotationMatrix2D(center,ang…

IDEA项目实践——Spring集成mybatis、spring当中的事务

系列文章目录 IDEA项目实践——创建Java项目以及创建Maven项目案例、使用数据库连接池创建项目简介 IDEWA项目实践——mybatis的一些基本原理以及案例 IDEA项目实践——动态SQL、关系映射、注解开发 IDEA项目实践——Spring框架简介,以及IOC注解 IDEA项目实践—…

ElementUI的MessageBox的按钮置灰且不可点击

// this.$confirmthis.$alert(这是一段内容, 标题名称, {confirmButtonText: 确定,confirmButtonCLass: confirmButton,beforeClose: (action,instance,done) > {if (action confirm) {return false} else {done()}});}.confirmButton {background: #ccc !important;cursor…

HDMI接口的PCB布局布线要求

高清多媒体接口(High Definition Multimedia Interface),简称:HDMI,是一种全数字化视频和声音发送接口,可以发送未压缩的音频及视频信号。随着技术的不断提升,HDMI的传输速率也不断的提升&#…

DoIP学习笔记系列:(六)满足AES128-CMAC算法的“安全认证”.dll生成实践

文章目录 1. 算法Demo2. 算法实现传送门 DoIP学习笔记系列:导航篇 AES128-CMAC算法在汽车电子控制单元的软件开发中涉及到安全相关的需求经经常用到,具体的算法原理请各位小伙伴自行百度,本篇主要向大家分享该算法如何集成到.dll文件中,在OTA、刷写等场景作为$27服务的安全…

24届近5年南京大学自动化考研院校分析

今天给大家带来的是南京大学控制考研分析 满满干货~还不快快点赞收藏 一、南京大学 学校简介 南京大学是一所历史悠久、声誉卓著的高等学府。其前身是创建于1902年的三江师范学堂,此后历经两江师范学堂、南京高等师范学校、国立东南大学、国立第四中…

集群、负载均衡集群、高可用集群简介,LVS模式和haproxy/nginx模式拓扑介绍

一.集群的定义 1.定义 2.分类 (1)负载均衡集群 (2)高可用集群 二.使用集群的意义 1.高性价比和性能比 2.高可用性 3.可伸缩性强 4.持久和透明性高 三.常见的两种集群模式拓扑 1.LVS集群模式 2.haproxy/nginx模式 四.常…