R语言使用协同过滤算法(usercf)解决投资推荐问题

针对投资者智能推荐金融产品是不是一个好主意?实际上许多互联网金融公司已经开始了这方面的尝试,陆金所的用户中心界面下方的‘为您推荐’栏目就是这方面的尝试,具体如下图:




这个就是典型的基于用户相似度做智能推荐的产品,现在我们就来揭开一种基于用户相似度做推荐算法的神秘面纱吧!!

本博客主要参考文献张丹在这篇博客http://blog.fens.me/r-mahout-usercf/里给出了协同过滤算法的R代码。


我主要使用R做模型,具体会使用到Matrix、arules、proxy、recommenderlab包,具体如下:

library(Matrix)

library(arules)
library(proxy)
library(recommenderlab)

这些安装包很容易在镜像网站找到,我这里就不列出具体地址了。


主要数据如下:



需要把它修改成如下格式:



我们需要把这种格式的数据转化为表现用户和产品关系的二维矩阵,如下图:



我是通过下面的函数做到的(by 张丹):

#将投资统计数据转化为用户与投资品的购买矩阵
FileDataModel<-function(file){
  data<-read.csv(file,na.string='NA',header=T)
  names(data)<-c("uid","iid","pref")
  user <- unique(data$uid)
  item <- unique(sort(data$iid))
  uidx <- match(data$uid, user)
  #为用户名建立唯一索引
  iidx <- match(data$iid, item)
  #为投资品建立唯一索引
  M <- matrix(0, length(user), length(item))
  #建立空矩阵以存放用户与投资品关系数据
  i <- cbind(uidx, iidx, pref=data$pref)
  #匹配用户名索引、投资品索引、投资喜好
  for(n in 1:nrow(i)){
    M[i[n,][1],i[n,][2]]<-i[n,][3]
  }
  #将喜好数据导入到关系矩阵
  dimnames(M)[[2]]<-item
  #修改矩阵列名
  M
}


在转化完关系矩阵之后,我们需要计算每个投资者之间的距离以确定与其他投资者的相似度,如下图:


代码如下:

#欧氏距离相似度算法,按行计算与其他用户的相似度
EuclideanDistanceSimilarity<-function(M){
  row<-nrow(M)
  s<-matrix(0, row, row)
  for(z1 in 1:row){
    for(z2 in 1:row){
      if(z1<z2){
        num<-intersect(which(M[z1,]!=0),which(M[z2,]!=0))
        #不同投资品只有不同投资者均有投资才可计算该列的相似度
        sum<-0
        for(z3 in num){
          sum<-sum+(M[z1,][z3]-M[z2,][z3])^2
        }
        
        s[z2,z1]<-length(num)/(1+sqrt(sum))
        #将欧氏距离倒置用来计算相似度,距离越小,相似度越大
        if(s[z2,z1]>1) s[z2,z1]<-1
        #将过大的相似度标准化为1
        if(s[z2,z1]< -1) s[z2,z1]<- -1 
        #将过小的相似度标准化为-1
        
        #print(paste(z1,z2));print(num);print(sum)
      }
    }
  }
  #补全三角矩阵
  ts<-t(s)
  w<-which(upper.tri(ts))
  s[w]<-ts[w]
  s
}


计算完用户之间的距离后,需要确认他们的近邻关系以备后面计算推荐产品,具体如下:



代码如下:

#最近邻算法,按相似度高低组建相似度最高的两个投资用户的近邻矩阵
NearestNUserNeighborhood<-function(S,n){
  row<-nrow(S)
  neighbor<-matrix(0, row, n)
  for(z1 in 1:row){
    for(z2 in 1:n){
      m<-which.max(S[,z1])
      #       print(paste(z1,z2,m,'\n'))
      neighbor[z1,][z2]<-m
      S[,z1][m]=0
    }
  }
  neighbor
}

注意:这里出现了后续我所恼火的最大问题,就是给大部分投资者推荐的都是前面几个用户的组合投资产品!为什么呢,下一章给大家讲一下原因。


然后开始基于近邻的投资习惯,推荐合适的投资产品给该投资者,结果如下图:



代码如下:

#推荐算法,推荐相似度最高的两用户均投资过的产品,并依据喜好权重给出推荐评分
UserBasedRecommender<-function(uid,n,M,S,N){
  row<-ncol(N)
  col<-ncol(M)
  r<-matrix(0, row, col)
  N1<-N[uid,]
  for(z1 in 1:length(N1)){
    num<-intersect(which(M[uid,]==0),which(M[N1[z1],]!=0)) #可计算的列
    #     print(num)
    
    for(z2 in num){
      #       print(paste("for:",z1,N1[z1],z2,M[N1[z1],z2],S[uid,N1[z1]]))
      r[z1,z2]=M[N1[z1],z2]*S[uid,N1[z1]]
    }
  }
  
  sum<-colSums(r)
  s2<-matrix(0, 2, col)
  for(z1 in 1:length(N1)){
    num<-intersect(which(colSums(r)!=0),which(M[N1[z1],]!=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[-2,]
  
  r2<-matrix(0, n, 2)
  rr<-sum/s2
  item <-dimnames(M)[[2]]
  for(z1 in 1:n){
    w<-which.max(rr)
    if(rr[w]>0.5){
      r2[z1,1]<-item[which.max(rr)]
      r2[z1,2]<-as.double(rr[w])
      rr[w]=0
    }
  }
  r2
}


#执行程序
FILE<-'F:/Rdata/hnjb/hnjbxtgltj2.csv'
NEIGHBORHOOD_NUM<-2
RECOMMENDER_NUM<-3


M<-FileDataModel(FILE)
#构建模型基础数据
S<-EuclideanDistanceSimilarity(M)
#构建相似度矩阵
N<-NearestNUserNeighborhood(S,NEIGHBORHOOD_NUM)
#构建近邻矩阵


#部分可执行,部分用户由于无相似数据没办法执行
R1<-UserBasedRecommender(1,RECOMMENDER_NUM,M,S,N);R1
R2<-UserBasedRecommender(2,RECOMMENDER_NUM,M,S,N);R2
R3<-UserBasedRecommender(3,RECOMMENDER_NUM,M,S,N);R3
R4<-UserBasedRecommender(4,RECOMMENDER_NUM,M,S,N);R4
R5<-UserBasedRecommender(5,RECOMMENDER_NUM,M,S,N);R5


做完这个推荐算法,我对结果极不满意,主要是出的结果价值不大,都推荐投资者去购买新手标了?!为什么呢?

我总结了一下,有以下三个问题:

1、数据基础方面的问题:

    1)产品不多,只有五个,可选择性太少,可能需要把产品拆得更细才ok——后续把明细产品投资数据拿过来做模型可能会更好;

    2)投资者太多,导致相似的概率较大——后续基于相似投资者的统计数据做推荐;

    3)另大部分投资者只投资一个产品,根本无法计算相似度——后续剔除部分单次投资数据尝试做推荐;

2、R语言实现问题:

    1)如张丹在博客中所说,for语句较多,执行起来较慢,我需要半个小时才能执行一次;

    2)近邻矩阵只有选择相似度最高的两人我觉得还是有点问题,我觉得如果投资者较多,可以根据投资者数量适当调整近邻矩阵容量,方便后续根据相似度最高的TOP100做投资品的统计分析;

3、模型相似度选择问题:

    1)本模型基于欧氏距离计算相似度,可能使用皮尔森相似度等来计算更好;

    2)后续的推荐模型是加权平均算法,也可以根据TOP100的相似度高低来做加权平均以获得更好的结果。


总之,上面只是推荐算法的简单实践,如果需要用它来解决实际问题,还需要在工作中多考虑实际情况,并根据情况调整自己的模型思路就行了。

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值