1. 程式人生 > >基於使用者的協同過濾演算法(Java實現或R語言實現

基於使用者的協同過濾演算法(Java實現或R語言實現

  協同過濾的步驟是:
  建立資料模型 —> 使用者相似度演算法 —>使用者近鄰演算法 —>推薦演算法。
  基於使用者的協同過濾演算法在Mahout庫中已經模組化了,通過4個模組進行統一的方法呼叫。首先,建立資料模型(DataModel),然後定義使用者的相似度演算法(UserSimilarity),接下來定義使用者近鄰演算法(UserNeighborhood ),最後呼叫推薦演算法(Recommender)完成計算過程。而基於物品的協同過濾演算法(ItemCF)過程也是類似的,去掉第三步計算使用者的近鄰演算法就行了。

  軟體環境:Win7 64位 + Eclipse4.4 +jdk1.6
  使用Java語言,借用Mahout庫裡的API,實現基於使用者的協同過濾演算法,從而進行商品推薦。
  1.資料集
  //testCF.csv  

1,101,5.0
1,102,3.0
1,103,2.5
2,101,2.0
2,102,2.5
2,103,5.0
2,104,2.0
3,101,2.5
3,104,4.0
3,105,4.5
3,107,5.0
4,101,5.0
4,103,3.0
4,104,4.5
4,106,4.0
5,101,4.0
5,102,3.0
5,103,2.0
5,104,4.0
5,105,3.5
5,106,4.0 

  該testCF.csv資料集中,第一列為使用者號UserID,第二列為商品號ItemID,第三列為評分Preference Value.
  2.借用Java裡Mahout庫,實現協同過濾演算法。
  //UserBased.java  

package com
.xie; import org.apache.mahout.cf.taste.common.TasteException; import org.apache.mahout.cf.taste.impl.common.LongPrimitiveIterator; import org.apache.mahout.cf.taste.impl.model.file.*; import org.apache.mahout.cf.taste.impl.neighborhood.*; import org.apache.mahout.cf.taste.impl.recommender.*;
import org.apache.mahout.cf.taste.impl.similarity.*; import org.apache.mahout.cf.taste.model.*; import org.apache.mahout.cf.taste.recommender.*; import org.apache.mahout.cf.taste.similarity.*; import java.io.*; import java.util.*; public class UserBased { final static int NEIGHBORHOOD_NUM = 2; final static int RECOMMENDER_NUM = 3; public static void main(String[] args) throws IOException, TasteException { String file = "src/data/testCF.csv"; DataModel model = new FileDataModel(new File(file)); UserSimilarity user = new EuclideanDistanceSimilarity(model); NearestNUserNeighborhood neighbor = new NearestNUserNeighborhood(NEIGHBORHOOD_NUM, user, model); Recommender r = new GenericUserBasedRecommender(model, neighbor, user); LongPrimitiveIterator iter = model.getUserIDs(); while (iter.hasNext()) { long uid = iter.nextLong(); List<RecommendedItem> list = r.recommend(uid, RECOMMENDER_NUM); System.out.printf("uid:%s", uid); for (RecommendedItem ritem : list) { System.out.printf("(%s,%f)", ritem.getItemID(), ritem.getValue()); } System.out.println(); } } }

  效果如下:

這裡寫圖片描述
圖(1) 協同過濾,從而進行商品推薦

  結果說明:
  對於uid=1的使用者,給他推薦計算得分最高的2個物品,104和106。
  對於uid=2的使用者,給他推薦計算得分最高的1個物品,105。
  對於uid=3的使用者,給他推薦計算得分最高的2個物品,103和102。
  對於uid=4的使用者,給他推薦計算得分最高的1個物品,102。
  對於uid=5的使用者,沒有推薦。
  用Java實現協同過濾的工程程式碼:
  http://download.csdn.net/detail/sanqima/9374529
  
  方法二:用R語言實現協同過濾演算法
  軟體環境:win7 64位 + RStudio 0.99 + R3.2.3
  //mahout1.R  

# part1 -------------------------------------------------------------------
##載入arules包
library(arules)

##建立模型矩陣
FileDataModel <- function(file){
    ##讀取CSV檔案到記憶體
    data <- read.csv(file,header = FALSE)  
    ##增加列名
    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
}


# part2 -------------------------------------------------------------------
##歐式距離相似度演算法
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
               if(s[z2,z1] < -1) s[z2,z1] <- -1

            }
        }
    }

    ts <- t(s)   ##補全三角矩陣
    w <- which(upper.tri(ts))
    s[w] <- ts[w]
    s      ##返回使用者相似度矩陣

}


# part3 -------------------------------------------------------------------
##使用者近鄰演算法
NearestNUserNeigborhood <- 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])
            neighbor[z1,][z2] <- m
            S[,z1][m]=0
        }
    }
    neighbor
}


# part4 -------------------------------------------------------------------
##推薦演算法
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))  
        for(z2 in num){
            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
}



# part5 -------------------------------------------------------------------

##呼叫演算法
setwd("G:\\myProject\\RDoc\\Unit2\\rChap2")
myFile <- "testCF.csv"
NeighborHodd_num <- 2 ##取兩個最大近鄰
Recommender_num <- 3  ##保留最多3個推薦結果

myM <- FileDataModel(myFile)
myS <- EuclideanDistanceSimilarity(myM)
myN <- NearestNUserNeigborhood(myS,NeighborHodd_num)

##對使用者user= 1的推薦結果
R1 <- UserBasedRecommender(1, Recommender_num,myM,myS,myN); R1

##對使用者user= 2的推薦結果
R2 <- UserBasedRecommender(2, Recommender_num,myM,myS,myN); R2

##對使用者user= 3的推薦結果
R3 <- UserBasedRecommender(3, Recommender_num,myM,myS,myN); R3

##對使用者user= 4的推薦結果
R4 <- UserBasedRecommender(4, Recommender_num,myM,myS,myN); R4

##對使用者user= 5的推薦結果
R5 <- UserBasedRecommender(5, Recommender_num,myM,myS,myN); R5

  效果如下:

這裡寫圖片描述
圖(2)用R語言實現協同過濾演算法