1. 程式人生 > >【Machine Learning】Mahout基於協同過濾(CF)的使用者推薦

【Machine Learning】Mahout基於協同過濾(CF)的使用者推薦

一、Mahout推薦演算法簡介

Mahout演算法框架自帶的推薦器有下面這些:

l  GenericUserBasedRecommender:基於使用者的推薦器,使用者數量少時速度快;

l  GenericItemBasedRecommender:基於商品推薦器,商品數量少時速度快,尤其當外部提供了商品相似度資料後效率更好;

l  SlopeOneRecommender:基於slope-one演算法的推薦器,線上推薦或更新較快,需要事先大量預處理運算,物品數量少時較好;

l  SVDRecommender:奇異值分解,推薦效果較好,但之前需要大量預處理運算;

l  KnnRecommender:基於k近鄰演算法(KNN),適合於物品數量較小時;

l  TreeClusteringRecommender:基於聚類的推薦器,線上推薦較快,之前需要大量預處理運算,使用者數量較少時效果好;

Mahout最常用的三個推薦器是上述的前三個,本文的例項僅“基於使用者的推薦器”做個實驗,其實大體原理都差不多。

二、基於協同過濾(CF)模型的使用者推薦

Mahout裡自帶的基本CF模型原理如下:

GenericUserBasedRecommender是基於使用者(user-based)的簡單推薦器實現類,推薦主要參照傳入的DataModel和UserNeighborhood,總體是三個步驟:

(1)從UserNeighborhood獲取當前使用者Ui

最相似的K個使用者集合{U1, U2, …Uk};

(2)從這K個使用者集合排除Ui的偏好商品,剩下的Item集合為{Item0, Item1, …Itemm};

(3)對Item集合裡每個Itemj計算Ui可能偏好程度值pref(Ui, Itemj),並把Item按此數值從高到低排序,前N個item推薦給使用者Ui

偏好程度值pref計算公式:


三、資料庫結構設計

建立資料庫mahoutDB,裡面建立表table1,具體表的結構如下所示,裡面包含4個特徵:userId,itemId, preference, date,分別代表使用者ID、商品ID、偏好分數、交易日期。


建好table1之後,表結構如下所示。

往table1裡匯入事先準備好的資料data.txt,

mysql>LOAD DATA LOCAL INFILE ‘data.txt’ INTO TABLE table1;

匯入完成過後資料如下所示。

使用者ID為1的記錄如下所示。

交易日期為20140825的記錄如下所示。

當中有一條記錄,比如使用者ID=2的選擇了商品202,偏好值為3.5。那麼之後應根據模型演算法,將相似使用者找出,並把相似使用者的偏好商品(排除userId=2他自己所選商品)推薦給使用者2。


四、原始碼

import java.util.List;
import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
import org.apache.mahout.cf.taste.impl.recommender.GenericUserBasedRecommender;
import org.apache.mahout.cf.taste.impl.similarity.PearsonCorrelationSimilarity;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.model.JDBCDataModel;
import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;

import com.mysql.MysqlDataSource;

/**
 *  mahout基於協同過濾(CF)的推薦
 *
 */
public class Mahout {
	public static void main(String[] args) throws TasteException {
		
		//(1)----連線資料庫部分
		MysqlDataSource dataSource = new MysqlDataSource();
		dataSource.setServerName("localhost");
		dataSource.setUser("admin");
		dataSource.setPassword("admin");
		dataSource.setDatabaseName("mahoutDB");
		//(2)----使用MySQLJDBCDataModel資料來源讀取MySQL裡的資料
		JDBCDataModel dataModel = new MySQLJDBCDataModel(dataSource, "table1", "userId", "itemId", "preference", "date");
		
		//(3)----資料模型部分
		 //把MySQLJDBCDataModel物件賦值給DataModel
		DataModel model = dataModel;
		//使用者相似度UserSimilarity:包含相似性度量和鄰居引數
		UserSimilarity similarity = new PearsonCorrelationSimilarity(model);
		//相鄰使用者UserNeighborhood
		UserNeighborhood neighborhood = new NearestNUserNeighborhood(2, similarity, model);
		//一旦確定相鄰使用者,一個普通的user-based推薦器被構建,構建一個GenericUserBasedRecommender推薦器需要資料來源DataModel,使用者相似性UserSimilarity,相鄰使用者相似度UserNeighborhood
		Recommender recommender = new GenericUserBasedRecommender(model, neighborhood, similarity);
		//向用戶1推薦2個商品
		List<RecommandedItem> recommendations = recommender.recommend(1, 2);
		for(RecommendedItem recommendation : recommendations){
			//輸出推薦結果
			System.out.println(recommendation);
		}
	}

}