Rhadoop实战:协同过滤

具体的数据和算法见:http://blog.fens.me/rhadoop-mapreduce-rmr/

这里仅给出Rhadoop代码的部分注释:

#加载rmr2包
library(rmr2)

#输入数据文件
train<-read.csv(file="small.csv",header=FALSE)
names(train)<-c("user","item","pref")

#使用rmr的hadoop格式,hadoop是默认设置。
rmr.options(backend = 'hadoop')

#把数据集存入HDFS
train.hdfs = to.dfs(keyval(train$user,train))
from.dfs(train.hdfs)

#####STEP 1, 建立物品的同现矩阵#####
# 1) 按用户分组,得到所有物品出现的组合列表。
train.mr<-mapreduce(train.hdfs, 
                    map = function(k, v) {keyval(k,v$item)},
                    #map形成<user,item>
                    reduce=function(k,v){
                        m<-merge(v,v);#通过merge合并item和item形成所有可能的两两物品组合
                        keyval(m$x,m$y);#两两组合一个为key一个为value
                      }
                    )
from.dfs(train.mr)
# 2) 对物品组合列表进行计数,建立物品的同现矩阵
step2.mr<-mapreduce(
  train.mr,
  map = function(k, v) {
    d<-data.frame(k,v)#将同现矩阵转为数据框,两两物品为一行
    d2<-ddply(d,.(k,v),count)#分组求次数
    #ddply(.data,.variables,.fun)针对数据.data按照分组.variables进行fun统计
    key<-d2$k
    val<-d2
    keyval(key,val)#key为item1,value是整个统计结果:item1 item2 frequency,这里item1表示物品1
  }#注意这里reduce=NULL
)
from.dfs(step2.mr)

##### 2. 建立用户对物品的评分矩阵####
train2.mr<-mapreduce(
  train.hdfs, #key为user,value为三列:user item pref
  map = function(k, v) {
    #df<-v[which(v$user==3),]
    df<-v#user item pref
    key<-df$item
    val<-data.frame(item=df$item,user=df$user,pref=df$pref)
    keyval(key,val)#key为item,value为:item user pref
  }
)
from.dfs(train2.mr)#key为item,value为:item user pref

####3. 合并同现矩阵 和 评分矩阵####
eq.hdfs<-equijoin(
  #equijoin(left.input,right.input,map.left,map.right,outer=c("","left","right","full"))from.dfs(result.mr)
  #left.input和right.input表示左边输入数据和右边输入数据
  #map.left是一个函数作用与左边输入数据,返回的key作为连接关键字,map.right针对右边输入数据
  #outer表示两边数据的连接方式
  left.input=step2.mr, #其中step.mr:key为item1,value是整个统计结果:item1 item2 frequency
  right.input=train2.mr,#train2.mr:key为item,value为:item user pre
  map.left=function(k,v){
    keyval(k,v)
  },
  map.right=function(k,v){
    keyval(k,v)
  },
  outer = c("left")#左连接(左边输入数据行全部存在)
)
from.dfs(eq.hdfs)#返回的结果key=NULL,value:item1 item2 frequency item=item1 user pref

####4. 计算推荐结果列表####
cal.mr<-mapreduce(
  input=eq.hdfs,#eq.hdfs的key=NULL,value为: item1 item2 frequency item=item1 user pref
  map=function(k,v){
    val<-v#value
    na<-is.na(v$user.r)#user
    if(length(which(na))>0) val<-v[-which(is.na(v$user.r)),]#剔除缺失ID的用户
    keyval(val$k.l,val)#key为item1,value为:item1 item2 frequency item=item1 user pref
  }
  ,reduce=function(k,v){
    val<-ddply(v,.(k.l,v.l,user.r),summarize,v=freq.l*pref.r)
    keyval(val$k.l,val)#key为item1,value为:item1 item2 user 推荐结果
  }
)
from.dfs(cal.mr)#key为item1,value为:item1 item2 user 推荐结果

####5. 按输入格式得到推荐评分列表####
result.mr<-mapreduce(
  input=cal.mr,#key为item1,value为:item1 item2 user 推荐结果
  map=function(k,v){
    keyval(v$user.r,v)#key为user,value:item1 item2 user 推荐结果
  }
  ,reduce=function(k,v){
    val<-ddply(v,.(user.r,v.l),summarize,v=sum(v))
    val2<-val[order(val$v,decreasing=TRUE),]#对推荐结果排序
    names(val2)<-c("user","item","pref")
    keyval(val2$user,val2)
  }
)
from.dfs(result.mr)#key为user,value:user item pref


你可能感兴趣的:(Rhadoop实战协同过滤)