为了账号安全,请及时绑定邮箱和手机立即绑定

SVD推荐算法python实现

标签:
Python

原文出处


经典的SVD算法,预测评分的的计算公式如下:

 

其中μ为评分的平均值,分别表示u用户的偏置量和i物品的偏置量。

从而,要优化的式子是如下形式:

 

要通过梯度下降优化的变量为四个,如下:


参考了一些代码,现在使用python实现如下

  1. import numpy as np  

  2. import random  

  3.   

  4.   

  5. class SVD:  

  6.     def __init__(self,mat,K=20):  

  7.         self.mat=np.array(mat)  

  8.         self.K=K  

  9.         self.bi={}  

  10.         self.bu={}  

  11.         self.qi={}  

  12.         self.pu={}  

  13.         self.avg=np.mean(self.mat[:,2])  

  14.         for i in range(self.mat.shape[0]):  

  15.             uid=self.mat[i,0]  

  16.             iid=self.mat[i,1]  

  17.             self.bi.setdefault(iid,0)  

  18.             self.bu.setdefault(uid,0)  

  19.             self.qi.setdefault(iid,np.random.random((self.K,1))/10*np.sqrt(self.K))  

  20.             self.pu.setdefault(uid,np.random.random((self.K,1))/10*np.sqrt(self.K))  

  21.     def predict(self,uid,iid):  #预测评分的函数  

  22.         #setdefault的作用是当该用户或者物品未出现过时,新建它的bi,bu,qi,pu,并设置初始值为0  

  23.         self.bi.setdefault(iid,0)  

  24.         self.bu.setdefault(uid,0)  

  25.         self.qi.setdefault(iid,np.zeros((self.K,1)))  

  26.         self.pu.setdefault(uid,np.zeros((self.K,1)))  

  27.         rating=self.avg+self.bi[iid]+self.bu[uid]+np.sum(self.qi[iid]*self.pu[uid]) #预测评分公式  

  28.         #由于评分范围在1到5,所以当分数大于5或小于1时,返回5,1.  

  29.         if rating>5:  

  30.             rating=5  

  31.         if rating<1:  

  32.             rating=1  

  33.         return rating  

  34.       

  35.     def train(self,steps=30,gamma=0.04,Lambda=0.15):    #训练函数,step为迭代次数。  

  36.         print('train data size',self.mat.shape)  

  37.         for step in range(steps):  

  38.             print('step',step+1,'is running')  

  39.             KK=np.random.permutation(self.mat.shape[0]) #随机梯度下降算法,kk为对矩阵进行随机洗牌  

  40.             rmse=0.0  

  41.             for i in range(self.mat.shape[0]):  

  42.                 j=KK[i]  

  43.                 uid=self.mat[j,0]  

  44.                 iid=self.mat[j,1]  

  45.                 rating=self.mat[j,2]  

  46.                 eui=rating-self.predict(uid, iid)  

  47.                 rmse+=eui**2  

  48.                 self.bu[uid]+=gamma*(eui-Lambda*self.bu[uid])    

  49.                 self.bi[iid]+=gamma*(eui-Lambda*self.bi[iid])  

  50.                 tmp=self.qi[iid]  

  51.                 self.qi[iid]+=gamma*(eui*self.pu[uid]-Lambda*self.qi[iid])  

  52.                 self.pu[uid]+=gamma*(eui*tmp-Lambda*self.pu[uid])  

  53.             gamma=0.93*gamma  

  54.             print('rmse is',np.sqrt(rmse/self.mat.shape[0]))  

  55.       

  56.     def test(self,test_data):  #gamma以0.93的学习率递减  

  57.           

  58.         test_data=np.array(test_data)  

  59.         print('test data size',test_data.shape)  

  60.         rmse=0.0  

  61.         for i in range(test_data.shape[0]):  

  62.             uid=test_data[i,0]  

  63.             iid=test_data[i,1]  

  64.             rating=test_data[i,2]  

  65.             eui=rating-self.predict(uid, iid)  

  66.             rmse+=eui**2  

  67.         print('rmse of test data is',np.sqrt(rmse/test_data.shape[0]))  

  68.               

  69.               

  70. def getData():   #获取训练集和测试集的函数  

  71.     import re  

  72.     f=open('C:/Users/xuwei/Desktop/data.txt','r')  

  73.     lines=f.readlines()  

  74.     f.close()  

  75.     data=[]  

  76.     for line in lines:  

  77.         list=re.split('\t|\n',line)  

  78.         if int(list[2]) !=0:    #提出评分0的数据,这部分是用户评论了但是没有评分的  

  79.             data.append([int(i) for i in list[:3]])  

  80.     random.shuffle(data)  

  81.     train_data=data[:int(len(data)*7/10)]  

  82.     test_data=data[int(len(data)*7/10):]  

  83.     print('load data finished')  

  84.     print('total data ',len(data))  

  85.     return train_data,test_data  

  86.       

  87.      

  88.   

  89. train_data,test_data=getData()  

  90. a=SVD(train_data,30)    

  91. a.train()  

  92. a.test(test_data)  

  93.           

  94.                    

  95.               

使用了自己爬取的豆瓣约130万的评分信息进行测试,分为测试组和训练组,训练组数据取70%,测试组占30%。

下面是测试结果:


最后训练集的RMSE为0.485,测试集0.654.


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消