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的相似度高低來做加權平均以獲得更好的結果。


總之,上面只是推薦算法的簡單實踐,如果需要用它來解決實際問題,還需要在工作中多考慮實際情況,並根據情況調整自己的模型思路就行了。

發佈了24 篇原創文章 · 獲贊 16 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章