R重写mahout中user-based协同过滤算法-注释篇

16 篇文章 1 订阅

声明:本篇是基于张丹《R的极客思想》书本中的内容,但张丹在代码中并未添加过多注释,本人最近在研究推荐系统,并将张丹的代码做了一些改动和详细注释贴上来供大家学习交流

#user-based 协同过滤推荐,3个近邻,2个推荐结果
#1.构建数据模型
FileDataModel<-function(file_name){
  user=unique(file_name$buyer_member_name)
  item=unique(file_name$store_name)		
  uidx=match(file_name$buyer_member_name,user)		#向量形式	
  iidx=match(file_name$store_name,item)
  #user-item评分矩阵,初始化值=0,可根据实际情况更改为其他值
  M=matrix(0,length(user),length(item))
  i=cbind(uidx,iidx,file_name$overall_rating)
  for (n in 1:nrow(i)) {
    M[i[n,][1],i[n,][2]]=i[n,][3]
  }
  #矩阵行列命名
  dimnames(M)[[2]]=item
  dimnames(M)[[1]]=user
  return(M)
}

#2.改进的欧式距离相似度算法
EuclideanDistanceSimilarity<-function(M){
  row=nrow(M)				#用户数
  s=matrix(0,row,row)		#初始化user-user相似度矩阵
  for (z1 in 1:row){
    for (z2 in 1:row){
	  #只计算下三角矩阵元素的值,不包含对角线元素
      if (z1<z2) {
        num=intersect(which(M[z2,] != 0),which(M[z1,] != 0))	#可进行计算的列-即都有正常的偏好评分
        sum=0
        for (z3 in num){
          sum=sum+(M[z1,][z3]-M[z2,][z3])^2
        }
        #下三角矩阵赋值
        s[z2,z1]=round(length(num)/(1+sqrt(sum)),3)
        #对算法阈值进行限制
        if (s[z2,z1]>1)  s[z2,z1]=1
        #if (s[z2,z1]<-1) s[z2,z1]=-1	
      }
    }
  }
  ts=t(s)	
  w=which(upper.tri(ts))	#默认不包含对角元素
  s[w]=ts[w]
  s
}

#3.用户最近邻算法,选出最近的前n个用户,传入客户相似度矩阵+近邻个数
NearestNUserNeighborhood<-function(s,n){
  row=nrow(s)
  neighbor=matrix(0,row,n)
  #user角度
  for (z1 in 1:row){
    for (z2 in 1:n){
      m=which.max(s[,z1])
	  #neighbor只存储索引
      neighbor[z1,z2]=m
      s[,z1][m]=0
    }
  }
  neighbor
}

#4.基于部分用户的推荐算法,对store_name进行推荐
#函数入参:buyer_member_name+recommender_num(推荐结果个数)+M(数据模型矩阵)+S(相似度矩阵)+N(近邻矩阵)
M=FileDataModel(entropy_data_frame)
S=EuclideanDistanceSimilarity(M)
N=NearestNUserNeighborhood(S,3)			#3个近邻


#uid_char为user name
UserBasedRecommender<-function(uid_char,n,M,S,N){
  uid=which(rownames(M)==uid_char)	#user name的行索引
  row=ncol(N)						#近邻个数
  col=ncol(M)						#store_name个数
  r=matrix(0,row,col)
  N1=N[uid,]						#N1-索引,length=近邻个数
  for (z1 in 1:length(N1)){
    num=intersect(which(M[uid,] == 0),which(M[N1[z1],] != 0))	#可计算的列,uid在评分矩阵上没有评分,而近邻有评分
    for (z2 in num){
      r[z1,z2]=M[N1[z1],z2] * S[uid,N1[z1]]		#评分乘相似度
    }
  }
  
  #过滤推荐矩阵结果
  sum=colSums(r)					#向量形式,每个store_name一个值
  s2=matrix(0,2,col)
  for (z1 in 1:length(N1)){
    num=intersect(which(colSums(r) != 0),which(M[N1[z1],] != 0))	#sum(评分乘相似度)不等于0,且近邻用户在store_name上的评分不等于0
    for (z2 in num){
      s2[1,][z2]=s2[1,][z2]+S[uid,N1[z1]]
      s2[2,][z2]=s2[2,][z2]+1		#计数
    }
  }
  
  s2[,which(s2[2,]==1)]=10000		#若在某个推荐上只有一个近邻有评分时,让s2矩阵对应的相似度无穷大
  s2=s2[-2,]
  
  r2=matrix(0,n,2)
  rr=sum/s2							#sum(评分乘相似度)/sum(相似度)					
  
  item=dimnames(M)[[2]]
  
  for (z1 in 1:n){
    w=which.max(rr)
    #0.5是可变化的值,即推荐阈值
    if(rr[w]>0.5){
      r2[z1,1]=item[which.max(rr)]
      r2[z1,2]=as.double(rr[w])
      rr[w]=0
    }
  }
  r2
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值