協同過濾的步驟是:
創建數據模型 —> 用戶相似度算法 —>用戶近鄰算法 —>推薦算法。
基於用戶的協同過濾算法在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(); } } }
效果如下:

結果說明:
對於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
效果如下:

轉自:http://blog.csdn.net/sanqima/article/details/50389765