〇.说明

本文的所有代码均可在 DML 找到,欢迎点星星。

一.引入

推荐系统(主要是CF)是我在参加百度的电影推荐算法比赛的时候才临时学的,虽然没拿什么奖,但是知识却是到手了,一直想写一篇关于推荐系统的文章总结下,这次借着完善DML写一下,权当是总结了。不过真正的推荐系统当然不会这么简单,往往是很多算法交错在一起,本文只是入门水平的总结罢了。 (本文所用测试数据是movielens100k)

本文采用的评测标准是RMSE,数值越小算法越好,在movielens100k 的 u1数据上对每个要求预测的评分输出训练集总的平均分,其RMSE是:

二.Item Based  and User Based

1.原理

Item-based和User-Based是CF算法中最基础的两个了,其算法思想很intuitive:

 User-based就是把与你有相同爱好的用户所喜欢的物品(并且你还没有评过分)推荐给你

(图自【1】)

Item-based则与之相反,把和你之前喜欢的物品近似的物品推荐给你:

(图自【1】)

更一般的,我们此次使用的数据集是要求你预测某个用户对某个item的评分,以Item-based为例,使用上面提到的算法思想就是检测该用户评过的所有物品和待预测物品的相似度,而两个物品的相似度我们可以找出所有同时对两个物品进行评价的评分,然后计算其皮尔逊相似度,按照相似度计算加权平均值即可,具体过程可以看下面的实现(和《集体智慧编程》中的类似)

2.实现

[python] view plaincopy
  1. from __future__ import division
  2. import numpy as np
  3. import scipy as sp
  4. class  Item_based_C:
  5. def __init__(self,X):
  6. self.X=np.array(X)
  7. print "the input data size is ",self.X.shape
  8. self.movie_user={}
  9. self.user_movie={}
  10. self.ave=np.mean(self.X[:,2])
  11. for i in range(self.X.shape[0]):
  12. uid=self.X[i][0]
  13. mid=self.X[i][1]
  14. rat=self.X[i][2]
  15. self.movie_user.setdefault(mid,{})
  16. self.user_movie.setdefault(uid,{})
  17. self.movie_user[mid][uid]=rat
  18. self.user_movie[uid][mid]=rat
  19. self.similarity={}
  20. pass
  21. def sim_cal(self,m1,m2):
  22. self.similarity.setdefault(m1,{})
  23. self.similarity.setdefault(m2,{})
  24. self.movie_user.setdefault(m1,{})
  25. self.movie_user.setdefault(m2,{})
  26. self.similarity[m1].setdefault(m2,-1)
  27. self.similarity[m2].setdefault(m1,-1)
  28. if self.similarity[m1][m2]!=-1:
  29. return self.similarity[m1][m2]
  30. si={}
  31. for user in self.movie_user[m1]:
  32. if user in self.movie_user[m2]:
  33. si[user]=1
  34. n=len(si)
  35. if (n==0):
  36. self.similarity[m1][m2]=1
  37. self.similarity[m2][m1]=1
  38. return 1
  39. s1=np.array([self.movie_user[m1][u] for u in si])
  40. s2=np.array([self.movie_user[m2][u] for u in si])
  41. sum1=np.sum(s1)
  42. sum2=np.sum(s2)
  43. sum1Sq=np.sum(s1**2)
  44. sum2Sq=np.sum(s2**2)
  45. pSum=np.sum(s1*s2)
  46. num=pSum-(sum1*sum2/n)
  47. den=np.sqrt((sum1Sq-sum1**2/n)*(sum2Sq-sum2**2/n))
  48. if den==0:
  49. self.similarity[m1][m2]=0
  50. self.similarity[m2][m1]=0
  51. return 0
  52. self.similarity[m1][m2]=num/den
  53. self.similarity[m2][m1]=num/den
  54. return num/den
  55. def pred(self,uid,mid):
  56. sim_accumulate=0.0
  57. rat_acc=0.0
  58. for item in self.user_movie[uid]:
  59. sim=self.sim_cal(item,mid)
  60. if sim<0:continue
  61. #print sim,self.user_movie[uid][item],sim*self.user_movie[uid][item]
  62. rat_acc+=sim*self.user_movie[uid][item]
  63. sim_accumulate+=sim
  64. #print rat_acc,sim_accumulate
  65. if sim_accumulate==0: #no same user rated,return average rates of the data
  66. return  self.ave
  67. return rat_acc/sim_accumulate
  68. def test(self,test_X):
  69. test_X=np.array(test_X)
  70. output=[]
  71. sums=0
  72. print "the test data size is ",test_X.shape
  73. for i in range(test_X.shape[0]):
  74. pre=self.pred(test_X[i][0],test_X[i][1])
  75. output.append(pre)
  76. #print pre,test_X[i][2]
  77. sums+=(pre-test_X[i][2])**2
  78. rmse=np.sqrt(sums/test_X.shape[0])
  79. print "the rmse on test data is ",rmse
  80. return output

sim_cal()为相似度计算,pred(uid,mid)预测uid号用户对mid号电影评分,然后我们在test()中计算RMSE,来看看结果:

可以看到与全部输出平均值比较有一定的提升,但是效果似乎并不好,因为这个算法确实有些简单,但是这个算法的思想对CF算法都很有指导意义

三.matrix factorization model 和 Baseline Predictors

这里没有实现是因为下面的SVD其实就是matrix factorization model和Baseline Predictor的结合,所以为了方便我们先在这里介绍这两个东西.

1.matrix factorization model

把我们的用户评分想象成一个表:

(图忘了是哪的了....)

每一行代表一个用户,每一列代表一个物品,这其实就是一个矩形,只是我们拥有的这个矩形可能是非常稀疏的,也就是我们知道的评分占总量很少,,但现在我们知道它是一个矩形,一个矩形自然可以表示为另两个矩形的乘积:

这也就是matrix factorization model的原理了,我们需要做的就是通过已有数据来学习右边的两个矩形,更intuitive的你可以把总的矩形里的每个评分看成是该用户的特征向量与物品特征向量的内积:(这里符号变得有些多,你理解了意思就成)

2.Baseline Predictors

Baseline Predictors就简单多了,我们设定μ是平均值,然后分别用bi和bu来代表具体用户和物品的“偏好”,也就是
这两个参数我们当然可以当成一个优化任务来计算,比如最小二乘:
也可以用比较快的方法来,因为实际上这就是经验似然:

四.SVD and ++ and  so on

(图来自【2】)

1.SVD及其衍生算法的原理

SVD算法其实就是上面介绍的matrix factorization的一种,加上baseline predictor算是一种优化而已,最简单的SVD是优化下面的Loss function:

采用随机梯度下降进行优化:

虽然看起来比较简单,但实际上对预测的效果已经超出Item-based很多了,而从SVD衍生出很多其它的算法,利用了更多的信息,我们在这里只予以介绍而不加实践。

SVD++

可以看到,SVD中并没有利用好一个用户评价了哪些电影这种信息,这代表无论评分高低,在看电影之前这些电影对他来说是有吸引力的,更一般的,如果你有用户查看过电影介绍的数据,同样也可以加以利用,SVD++就是加入了这些信息:

R(u)表示用户rate过的电影,这样加入参数后使模型更加复杂了,但其效果也就更好了,具体的优化过程就不贴了,反正还是那样,对Loss function求导而已。

timeSVD++

无论是netflix还是movielens的数据,它的最后一列是用户作出该评价的时间,timeSVD++就是将时间这个信息加以了利用,比较直观的理解就是影片的受欢迎程度可能是随着时间的变化而变化的,某些电影可能还具有周期性,如何加入这个信息呢?:

是pu成为一个随着时间变化而变化的参数:

2.SVD的实现

说了那么多高大上的衍生算法,我们还是来实现一下最基础的SVD吧:

[python] view plaincopy
  1. from __future__ import division
  2. import numpy as np
  3. import scipy as sp
  4. from numpy.random import random
  5. class  SVD_C:
  6. def __init__(self,X,k=20):
  7. '''''
  8. k  is the length of vector
  9. '''
  10. self.X=np.array(X)
  11. self.k=k
  12. self.ave=np.mean(self.X[:,2])
  13. print "the input data size is ",self.X.shape
  14. self.bi={}
  15. self.bu={}
  16. self.qi={}
  17. self.pu={}
  18. self.movie_user={}
  19. self.user_movie={}
  20. for i in range(self.X.shape[0]):
  21. uid=self.X[i][0]
  22. mid=self.X[i][1]
  23. rat=self.X[i][2]
  24. self.movie_user.setdefault(mid,{})
  25. self.user_movie.setdefault(uid,{})
  26. self.movie_user[mid][uid]=rat
  27. self.user_movie[uid][mid]=rat
  28. self.bi.setdefault(mid,0)
  29. self.bu.setdefault(uid,0)
  30. self.qi.setdefault(mid,random((self.k,1))/10*(np.sqrt(self.k)))
  31. self.pu.setdefault(uid,random((self.k,1))/10*(np.sqrt(self.k)))
  32. def pred(self,uid,mid):
  33. self.bi.setdefault(mid,0)
  34. self.bu.setdefault(uid,0)
  35. self.qi.setdefault(mid,np.zeros((self.k,1)))
  36. self.pu.setdefault(uid,np.zeros((self.k,1)))
  37. if (self.qi[mid]==None):
  38. self.qi[mid]=np.zeros((self.k,1))
  39. if (self.pu[uid]==None):
  40. self.pu[uid]=np.zeros((self.k,1))
  41. ans=self.ave+self.bi[mid]+self.bu[uid]+np.sum(self.qi[mid]*self.pu[uid])
  42. if ans>5:
  43. return 5
  44. elif ans<1:
  45. return 1
  46. return ans
  47. def train(self,steps=20,gamma=0.04,Lambda=0.15):
  48. for step in range(steps):
  49. print 'the ',step,'-th  step is running'
  50. rmse_sum=0.0
  51. kk=np.random.permutation(self.X.shape[0])
  52. for j in range(self.X.shape[0]):
  53. i=kk[j]
  54. uid=self.X[i][0]
  55. mid=self.X[i][1]
  56. rat=self.X[i][2]
  57. eui=rat-self.pred(uid,mid)
  58. rmse_sum+=eui**2
  59. self.bu[uid]+=gamma*(eui-Lambda*self.bu[uid])
  60. self.bi[mid]+=gamma*(eui-Lambda*self.bi[mid])
  61. temp=self.qi[mid]
  62. self.qi[mid]+=gamma*(eui*self.pu[uid]-Lambda*self.qi[mid])
  63. self.pu[uid]+=gamma*(eui*temp-Lambda*self.pu[uid])
  64. gamma=gamma*0.93
  65. print "the rmse of this step on train data is ",np.sqrt(rmse_sum/self.X.shape[0])
  66. #self.test(test_data)
  67. def test(self,test_X):
  68. output=[]
  69. sums=0
  70. test_X=np.array(test_X)
  71. #print "the test data size is ",test_X.shape
  72. for i in range(test_X.shape[0]):
  73. pre=self.pred(test_X[i][0],test_X[i][1])
  74. output.append(pre)
  75. #print pre,test_X[i][2]
  76. sums+=(pre-test_X[i][2])**2
  77. rmse=np.sqrt(sums/test_X.shape[0])
  78. print "the rmse on test data is ",rmse
  79. return output

行数各种少有木有,我们测试一下:在向量长度k=30,执行轮数steps=25,参数gamma=0.04,Lambda=0.15

[python] view plaincopy
  1. a=SVD_C(train_X,30)
  2. a.train()
  3. a.test(test_X)

结果:

可以达到0.927左右,比之前的提高已经很多了,事实上如果你对参数进一步优化,并且增加向量大小和迭代步数,在movielens1M的数据上可以到到0.87左右的rmse,这就是最烦人的调参了,我就不在这里详述这种痛苦的经历了.......

五.CF with RBM

又到了相当的蛋疼RBM了,RBM的CF,单模型效果和SVD相似,只是error在不同的地方,所以结合起来可以提升效果,总觉得RBM不够intuitive,这次实现也遇到很多困难,所以这一节的质量不高,见谅

1.原理

首先……你得了解一下RBM……一个能量模型,Hinton的招牌作品,DeepLearning就是由这个火起来的(DBN)

这里我就不细讲RBM了,有兴趣大家找下面的ref看,直接看看CF FOR RBM这个模型吧:

严格来说这是condional RBM,基本思路是把V用softmax的形式表示成一个向量,然后去掉改用户没有评价的部分,作为RBM的V层,共用一个Hidden层,主要参数有:Vik,Wikj,Dij,vb(bias of visual layer), hb(bias of hidden)。

这是主要的学习过程,其中的公式参见【3】:

看着是有点烦,但如果你看懂了这个结构,还是很简单明了的,与普通的RBM比较,只是在visible层的sample和update有一定的变化,主要体现在:a)sample一个v[item]的时候按随机值向上累计v[item][1...5],超过随机值的那个值设置为1,其它为0;b)update的时候按照softmax的格式来处理每一组v[item]。

2.实现

这个实现写了两三天了,而且目前效果不好,RMSE只能到0.98,不知道哪里出了问题,我已经排查过好几次了,不过还是发到这里希望大家能够帮我找出问题,代码可读性也不是很好,因为为了向量化使用了大量的切片操作,堪称丑陋,绝对没有一些C++版本的代码可读性好,但还是发在这里吧,希望有人能加以指正,万分感谢。sigh……
[python] view plaincopy
  1. from __future__ import division
  2. import numpy as np
  3. import scipy as sp
  4. from numpy.random import normal,random,uniform
  5. '''''
  6. this code still have some problem,I can only get 0.98 rmse on movielens data
  7. If you can figure it out,PLEASE!!! tell me .
  8. '''
  9. class TEMP:
  10. def __init__(self):
  11. self.AccVH=None
  12. self.CountVH=None
  13. self.AccV=None
  14. self.temp.CountV=None
  15. self.temp.AccH=None
  16. class  CF_RMB_C:
  17. def __init__(self,X,UserNum=943,HiddenNum=30,ItemNum=1682,Rate=5):
  18. self.X=np.array(X)
  19. self.HiddenNum=HiddenNum
  20. self.ItemNum=ItemNum
  21. self.UserNum=UserNum
  22. self.Rate=Rate
  23. self.movie_user={}
  24. self.user_movie={}
  25. self.bik=np.zeros((self.ItemNum,self.Rate))
  26. self.Momentum={}
  27. self.Momentum['bik']=np.zeros((self.ItemNum,self.Rate))
  28. self.UMatrix=np.zeros((self.UserNum,self.ItemNum))
  29. self.V=np.zeros((self.ItemNum,self.Rate))
  30. for i in range(self.X.shape[0]):
  31. uid=self.X[i][0]-1
  32. mid=self.X[i][1]-1
  33. rat=self.X[i][2]-1
  34. self.UMatrix[uid][mid]=1
  35. self.bik[mid][rat]+=1
  36. self.movie_user.setdefault(mid,{})
  37. self.user_movie.setdefault(uid,{})
  38. self.movie_user[mid][uid]=rat
  39. self.user_movie[uid][mid]=rat
  40. pass
  41. self.W=normal(0,0.01,(self.ItemNum,self.Rate,HiddenNum))
  42. self.Momentum['W']=np.zeros(self.W.shape)
  43. self.initialize_bik()
  44. self.bj=np.zeros((HiddenNum,1)).flatten(1)
  45. self.Momentum['bj']=np.zeros(self.bj.shape)
  46. self.Dij=np.zeros((self.ItemNum,self.HiddenNum))
  47. self.Momentum['Dij']=np.zeros((self.ItemNum,self.HiddenNum))
  48. def initialize_bik(self):
  49. for i in range(self.ItemNum):
  50. total=np.sum(self.bik[i])
  51. if total>0:
  52. for k in range(self.Rate):
  53. if self.bik[i][k]==0:
  54. self.bik[i][k]=-10
  55. else:
  56. self.bik[i][k]=np.log(self.bik[i][k]/total)
  57. def test(self,test_X):
  58. output=[]
  59. sums=0
  60. test_X=np.array(test_X)
  61. #print "the test data size is ",test_X.shape
  62. for i in range(test_X.shape[0]):
  63. pre=self.pred(test_X[i][0]-1,test_X[i][1]-1)
  64. #print test_X[i][2],pre
  65. output.append(pre)
  66. #print pre,test_X[i][2]
  67. sums+=(pre-test_X[i][2])**2
  68. rmse=np.sqrt(sums/test_X.shape[0])
  69. print "the rmse on test data is ",rmse
  70. return output
  71. def pred(self,uid,mid):
  72. V=self.clamp_user(uid)
  73. pj=self.update_hidden(V,uid)
  74. vp=self.update_visible(pj,uid,mid)
  75. ans=0
  76. for i in range(self.Rate):
  77. ans+=vp[i]*(i+1)
  78. return ans
  79. def clamp_user(self,uid):
  80. V=np.zeros(self.V.shape)
  81. for i in self.user_movie[uid]:
  82. V[i][self.user_movie[uid][i]]=1
  83. return V
  84. def train(self,para,test_X,cd_steps=3,batch_size=30,numEpoch=100,Err=0.00001):
  85. for epo in range(numEpoch):
  86. print 'the ',epo,'-th  epoch is running'
  87. kk=np.random.permutation(range(self.UserNum))
  88. bt_count=0
  89. while bt_count<=self.UserNum:
  90. btend=min(self.UserNum,bt_count+batch_size)
  91. users=kk[bt_count:btend]
  92. temp=TEMP
  93. temp.AccVH=np.zeros(self.W.shape)
  94. temp.CountVH=np.zeros(self.W.shape)
  95. temp.AccV=np.zeros(self.V.shape)
  96. temp.CountV=np.zeros(self.V.shape)
  97. temp.AccH=np.zeros(self.bj.shape)
  98. watched=np.zeros(self.UMatrix[0].shape)
  99. for user in users:
  100. watched[self.UMatrix[user]==1]=1
  101. sv=self.clamp_user(user)
  102. pj=self.update_hidden(sv,user)
  103. temp=self.accum_temp(sv,pj,temp,user)
  104. #AccVH+=pj*
  105. for step in range(cd_steps):
  106. sh=self.sample_hidden(pj)
  107. vp=self.update_visible(sh,user)
  108. sv=self.sample_visible(vp,user)
  109. pj=self.update_hidden(sv,user)
  110. deaccum_temp=self.deaccum_temp(sv,pj,temp,user)
  111. self.updateall(temp,batch_size,para,watched)
  112. #updateall============================================
  113. bt_count+=batch_size
  114. self.test(test_X)
  115. def accum_temp(self,V,pj,temp,uid):
  116. for i in self.user_movie[uid]:
  117. temp.AccVH[i]+=np.dot(V[i].reshape(-1,1),pj.reshape(1,-1))
  118. temp.CountVH[i]+=1
  119. temp.AccV[i]+=V[i]
  120. temp.CountV[i]+=1
  121. temp.AccH+=pj
  122. return temp
  123. def deaccum_temp(self,V,pj,temp,uid):
  124. for i in self.user_movie[uid]:
  125. temp.AccVH[i]-=np.dot(V[i].reshape(-1,1),pj.reshape(1,-1))
  126. temp.AccV[i]-=V[i]
  127. temp.AccH-=pj
  128. return temp
  129. def updateall(self,temp,batch_size,para,watched):
  130. delatW=np.zeros(temp.CountVH.shape)
  131. delatBik=np.zeros(temp.CountV.shape)
  132. delatW[temp.CountVH!=0]=temp.AccVH[temp.CountVH!=0]/temp.CountVH[temp.CountVH!=0]
  133. delatBik[temp.CountV!=0]=temp.AccV[temp.CountV!=0]/temp.CountV[temp.CountV!=0]
  134. delataBj=temp.AccH/batch_size
  135. self.Momentum['W'][temp.CountVH!=0]=self.Momentum['W'][temp.CountVH!=0]*para['Momentum']
  136. self.Momentum['W'][temp.CountVH!=0]+=para['W']*(delatW[temp.CountVH!=0]-para['weight_cost']*self.W[temp.CountVH!=0])
  137. self.W[temp.CountVH!=0]+=self.Momentum['W'][temp.CountVH!=0]
  138. self.Momentum['bik'][temp.CountV!=0]=self.Momentum['bik'][temp.CountV!=0]*para['Momentum']
  139. self.Momentum['bik'][temp.CountV!=0]+=para['bik']*delatBik[temp.CountV!=0]
  140. self.bik[temp.CountV!=0]+=self.Momentum['bik'][temp.CountV!=0]
  141. self.Momentum['bj']=self.Momentum['bj']*para['Momentum']
  142. self.Momentum['bj']+=para['bj']*delataBj
  143. self.bj+=self.Momentum['bj']
  144. for i in range(self.ItemNum):
  145. if watched[i]==1:
  146. self.Momentum['Dij'][i]=self.Momentum['Dij'][i]*para['Momentum']
  147. self.Momentum['Dij'][i]+=para['D']*temp.AccH/batch_size
  148. self.Dij[i]+=self.Momentum['Dij'][i]
  149. np.seterr(all='raise')
  150. def update_hidden(self,V,uid):
  151. r=self.UMatrix[uid]
  152. hp=None
  153. for i in self.user_movie[uid]:
  154. if hp==None:
  155. hp=np.dot(V[i],self.W[i]).flatten(1)
  156. else:
  157. hp+=np.dot(V[i],self.W[i]).flatten(1)
  158. pj=1/(1+np.exp(-self.bj-hp+np.dot(r,self.Dij).flatten(1)))
  159. #pj=1/(1+np.exp(-self.bj-hp))
  160. return pj
  161. def sample_hidden(self,pj):
  162. sh=uniform(size=pj.shape)
  163. for i in range(sh.shape[0]):
  164. if sh[i]<pj[i]:
  165. sh[i]=1.0
  166. else:
  167. sh[i]=0.0
  168. return sh
  169. def update_visible(self,sh,uid,mid=None):
  170. if mid==None:
  171. vp=np.zeros(self.V.shape)
  172. for i in self.user_movie[uid]:
  173. vp[i]=np.exp(self.bik[i]+np.dot(self.W[i],sh))
  174. vp[i]=vp[i]/np.sum(vp[i])
  175. return vp
  176. vp=np.exp(self.bik[mid]+np.dot(self.W[mid],sh))
  177. vp=vp/np.sum(vp)
  178. return vp
  179. def sample_visible(self,vp,uid):
  180. sv=np.zeros(self.V.shape)
  181. for i in self.user_movie[uid]:
  182. r=uniform()
  183. k=0
  184. for k in range(self.Rate):
  185. r-=vp[i][k]
  186. if r<=0:break
  187. sv[i][k]=1
  188. return sv

【Reference】

【1】探索推荐引擎内部的秘密,第 2 部分: 深入推荐引擎相关算法 – 协同过滤 http://topgeek.org/?p=365
【2】Yehuda Koren and Robert Bell,    ”Advances in Collaborative Filtering”
【3】Gilles Louppe and Pierre Geurts,"Collaborative filtering Scalable approaches using restricted Boltzmann machines"
【4】SALAKHUTDINOV, R., MNIH, A., ANDHINTON, G. E. Restricted Boltzmann machines for collaborative filtering. InProceedings of the 24th international con-ference on Machine learning (2007), ACM, p. 798.

【推荐精读】从item-base到svd再到rbm,多种Collaborative Filtering(协同过滤算法)从原理到实现相关推荐

  1. 推荐系统(一)基于协同过滤算法开发离线推荐

    什么是离线推荐 所谓的离线推荐其实就是根据用户产生的行为日志,后台设定一个离线统计算法和离线推荐算法的任务来对这些行为日志进行周期性的统计,统计过后的结果数据为前台或者实时分析提供数据的支撑.离线推荐 ...

  2. 【机器学习项目实战】Python基于协同过滤算法进行电子商务网站用户行为分析及服务智能推荐

    说明:这是一个机器学习实战项目(附带数据+代码+文档+代码讲解),如需数据+代码+文档+代码讲解可以直接到文章最后获取. 1.项目背景 电子商务网站数量迅速上升,将电子商务网站浏览者变为实际消费者,满 ...

  3. 协同过滤算法_机器学习 | 简介推荐场景中的协同过滤算法,以及SVD的使用

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是机器学习专题的第29篇文章,我们来聊聊SVD在上古时期的推荐场景当中的应用. 推荐的背后逻辑 有没有思考过一个问题,当我们在淘宝或者是 ...

  4. 【推荐算法】协同过滤算法——基于用户 Java实现

    只是简单谢了一个Demo,先贴上GitHub地址. https://github.com/wang135139/recommend-system 基本概念就不过多介绍了,相信能看明白的都了解.如果想了 ...

  5. 基于协同过滤算法的电影推荐系统设计(二) - ALS算法详解

    0 系列文章目录 0.1 基于协同过滤算法的电影推荐系统设计(一) - 项目简介 0.2 基于协同过滤算法的电影推荐系统设计(二) - 推荐系统介绍 ALS是alternating least squ ...

  6. 探秘推荐引擎之协同过滤算法小综述

    数学大神.统计学大神和数据挖掘推荐大神请关注. 一.数学期望的理解 早些时候,法国有两个大数学家,一个叫做布莱士·帕斯卡,一个叫做费马.帕斯卡认识两个赌徒,这两个赌徒向他提出了一个问题.他们说,他俩下 ...

  7. 协同过滤算法_基于Mahout的协同过滤推荐算法

    1协同过滤 基于物品的协同过滤 对物品进行相似度计算,然后再进行推荐. 基于用户的协同过滤 基于用户的协同过滤算法是通过用户的历史行为数据发现用户对商品或内容的喜欢,并对这些喜好进行度量和打分.根据不 ...

  8. 推荐 | 微软SAR近邻协同过滤算法拆解(二)

    推荐 | 微软SAR近邻协同过滤算法解析(一)前面这篇介绍了整个SAR算法,算法本身比较容易理解.本篇主要对一下里面有趣的小函数. 文章目录 1 对角方阵求jaccard / lift 2 矩阵取to ...

  9. 个性化智能推荐(协同过滤算法)技术研究

    个性化智能推荐(协同过滤算法)技术研究 一.  协同过滤推荐(Collaborative Filtering简称 CF)        协同过滤技术是目前推荐系统中最成功和应用最广泛的技术,在理论研究 ...

  10. Slope one—个性化推荐中最简洁的协同过滤算法

    Slope One 是一系列应用于 协同过滤的算法的统称.由 Daniel Lemire和Anna Maclachlan于2005年发表的论文中提出. [1]有争议的是,该算法堪称基于项目评价的non ...

最新文章

  1. 使用Varnish+ESI实现静态页面的局部缓存
  2. 如何得到数据库中所有表字段及字段中文描述
  3. g_thread_init
  4. 初中数学503个必考知识点_2020年中考数学必考知识点公布,考生高分、满分提分必备神器...
  5. adt变频器故障代码ol2_误诊实例换来的变频器维修经验
  6. Verilog实现的多个按键消抖(具体模块可用)
  7. ESP8266 MQTT
  8. 光栅渲染器(二)画线
  9. 激情巴布部落畅快一日游
  10. ADB Interface 找不到驱动程序
  11. 利用Python进行数据分析之超市零售分析
  12. 个人投资理财太平亿康的五种方式
  13. MCU学习笔记_IO引脚复用和映射
  14. 关于手机输入法的一些点子
  15. sql重复数据只取一条记录
  16. tensor转换为list
  17. 金蝶BOS,界面区域按钮增加权限控制
  18. 央行回应备付金存管办法修改:可及时监测风险 提高清算效率
  19. GSEA文件准备及表达相关性分析(R语言)
  20. 中职计算机专业选修课程,对中职计算机专业课程改革的思考

热门文章

  1. H3C交换机创建用户
  2. 华为 “VRRP” 多备份组
  3. ELK详解(三)——Elasticsearch部署优化
  4. LAMP+Varnish缓存详解(一)——Varnish简介
  5. CTF中一点进制转换脚本记录
  6. vim编辑时遇到E325: ATTENTION Found a swap file by the name ./.backu.sh.swp错误代码的解决办法
  7. 微服务调用链基本原理与使用
  8. linux/unix 上那些炫酷的命令行工具(一)
  9. Base58编码的长度是如何计算的?
  10. SQL Server 全文索引的管理