トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS

Mahout:サンプル1:はじめてのレコメンド のバックアップの現在との差分(No.1)


  • 追加された行はこの色です。
  • 削除された行はこの色です。
[[Mahout:環境構築]]

*Mahout:サンプル1:はじめてのレコメンド [#xd802de1]
Mahoutを使った初めてのレコメンドです。

まあ、Mahout本に記載されているサンプルを実行してるだけですがw

※Mahout本にはimportするクラスとか書いてないけど、きっとサンプルソースはコーディングせずにDLして使ってね!ってことなんだよねw それとも、それぐらい解決できない人はそもそも対象外ですよ、ってことなのかなw

***サンプルコード [#h23b3875]
うだうだ長いですが、端的には
-DataModelにデータを食わせて
-Simirarityを計算させて
-Neighborhoodを計算させて
-そいつらを元にRecommenderを生成して
-RecommenderにレコメンドするユーザID(1)と提示(レコメンデーション)させるアイテム数(1)を渡しているってことです。

■RecommenderIntro.java
 package test1;
 
 import java.io.File;
 import java.util.List;
 
 import org.apache.mahout.cf.taste.impl.model.file.FileDataModel;
 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.neighborhood.UserNeighborhood;
 import org.apache.mahout.cf.taste.recommender.RecommendedItem;
 import org.apache.mahout.cf.taste.recommender.Recommender;
 import org.apache.mahout.cf.taste.similarity.UserSimilarity;
 
 
 public class RecommenderIntro {
 
 	/**
 	 * @param args
 	 */
 	public static void main(String[] args) throws Exception{
 		DataModel model = new FileDataModel(new File("data/data1/intro.csv"));
 		
 		UserSimilarity similarity = new PearsonCorrelationSimilarity(model);
 		
 		UserNeighborhood neighborhood = new NearestNUserNeighborhood(2, similarity, model);
 		
 		Recommender recommender = new GenericUserBasedRecommender(
 				model, neighborhood, similarity);
 		
 		List<RecommendedItem> recommendations = recommender.recommend(1, 1);
 		
 		for (RecommendedItem recommendation : recommendations){
 			System.out.println(recommendation);
 		}
 	}
 }

サンプルで使用するデータは「data/data1/intro.csv」としてます。

■data/data1/intro.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,5
 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

して、サンプルの実行結果は以下のとおり。
 SLF4J: Class path contains multiple SLF4J bindings.
 SLF4J: Found binding in [jar:file:/opt/extend/mahout/Mahout1/lib-mahout/lib/slf4j-jcl-1.6.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
 SLF4J: Found binding in [jar:file:/opt/extend/mahout/Mahout1/lib-mahout/lib/slf4j-log4j12-1.6.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
 SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
 13/04/12 22:49:17 INFO file.FileDataModel: Creating FileDataModel for file data/data1/intro.csv
 13/04/12 22:49:17 INFO file.FileDataModel: Reading file info...
 13/04/12 22:49:17 INFO file.FileDataModel: Read lines: 21
 13/04/12 22:49:17 INFO model.GenericDataModel: Processed 5 users
 RecommendedItem[item:104, value:4.257081]

ほっほー、とりあえず、結果が出力されましたw

結果としては、「ユーザ1に1つアイテムをレコメンドせい」という要求に対して「104ってやつがスコア4.26でおすすめです」と言うことですな。

じゃあ、レコメンドさせるアイテムを2にすると以下のようになります。

ソース上のここ
 List<RecommendedItem> recommendations = recommender.recommend(1, 1);
を
 List<RecommendedItem> recommendations = recommender.recommend(1, 2);
に修正して実行!っと。するとこんな感じです。

 SLF4J: Class path contains multiple SLF4J bindings.
 SLF4J: Found binding in [jar:file:/opt/extend/mahout/Mahout1/lib-mahout/lib/slf4j-jcl-1.6.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
 SLF4J: Found binding in [jar:file:/opt/extend/mahout/Mahout1/lib-mahout/lib/slf4j-log4j12-1.6.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
 SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
 13/04/12 23:21:42 INFO file.FileDataModel: Creating FileDataModel for file data/data1/intro.csv
 13/04/12 23:21:43 INFO file.FileDataModel: Reading file info...
 13/04/12 23:21:43 INFO file.FileDataModel: Read lines: 21
 13/04/12 23:21:43 INFO model.GenericDataModel: Processed 5 users
 RecommendedItem[item:104, value:4.257081]
 RecommendedItem[item:106, value:4.0]

なるほど、2つのアイテムがレコメンドされた!そりゃあそうかw

***レコメンダの評価 [#ce5bd6a3]
Mahout本では、いきなり次に、レコメンダの評価の話に移ります。

「評価ってなに?」って感じだけど、3回くらい読んで何となくわかった気になってます。

まあ、評価って「存在するデータの一部を使用してレコメンダを作成し、残りの一部(全部)のデータを使って、レコメンダで計算させた結果と、実際の値を比較し、評価する」ってこと見たいです。

上のサンプルを、評価を実行するように改変したコードは以下のとおり。なお、データは変わりません。

■RecommenderIntroAndEvaluation.java
 package test1;
 
 import java.io.File;
 
 import org.apache.mahout.cf.taste.common.TasteException;
 import org.apache.mahout.cf.taste.eval.RecommenderBuilder;
 import org.apache.mahout.cf.taste.eval.RecommenderEvaluator;
 import org.apache.mahout.cf.taste.impl.eval.AverageAbsoluteDifferenceRecommenderEvaluator;
 import org.apache.mahout.cf.taste.impl.model.file.FileDataModel;
 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.neighborhood.UserNeighborhood;
 import org.apache.mahout.cf.taste.recommender.Recommender;
 import org.apache.mahout.cf.taste.similarity.UserSimilarity;
 import org.apache.mahout.common.RandomUtils;
 
 
 public class RecommenderIntroAndEvaluation {
 
 	/**
 	 * @param args
 	 */
 	public static void main(String[] args) throws Exception{
 		RandomUtils.useTestSeed();
 		DataModel model = new FileDataModel(new File("data/data1/intro.csv"));
 		
 		RecommenderEvaluator evaluator = 
 				new AverageAbsoluteDifferenceRecommenderEvaluator();
 		
 		RecommenderBuilder builder = new RecommenderBuilder(){
 			@Override
 			public Recommender buildRecommender(DataModel model) 
 					throws TasteException {
 				UserSimilarity similarity = 
 						new PearsonCorrelationSimilarity(model);
 				
 				UserNeighborhood neighborhood = 
 						new NearestNUserNeighborhood(2, similarity, model);
 				
 				return new GenericUserBasedRecommender(
 						model, neighborhood, similarity);				
 			}
 		};
 		// 70%のデータを使用してRecommenderを作成し、30%のデータを使用して評価を実行
 		double score = evaluator.evaluate(builder,null,model,0.7,1.0);
 		System.out.println(score);
 	}
 }

実行結果は以下のとおり。

 SLF4J: Class path contains multiple SLF4J bindings.
 SLF4J: Found binding in [jar:file:/opt/extend/mahout/Mahout1/lib-mahout/lib/slf4j-jcl-1.6.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
 SLF4J: Found binding in [jar:file:/opt/extend/mahout/Mahout1/lib-mahout/lib/slf4j-log4j12-1.6.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
 SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
 13/04/12 23:38:18 INFO file.FileDataModel: Creating FileDataModel for file data/data1/intro.csv
 13/04/12 23:38:18 INFO file.FileDataModel: Reading file info...
 13/04/12 23:38:18 INFO file.FileDataModel: Read lines: 21
 13/04/12 23:38:18 INFO model.GenericDataModel: Processed 5 users
 13/04/12 23:38:18 INFO eval.AbstractDifferenceRecommenderEvaluator: Beginning evaluation using 0.7 of FileDataModel[dataFile:/opt/extend/mahout/Mahout1/data/data1/intro.csv]
 13/04/12 23:38:18 INFO model.GenericDataModel: Processed 5 users
 13/04/12 23:38:18 INFO eval.AbstractDifferenceRecommenderEvaluator: Beginning evaluation of 3 users
 13/04/12 23:38:18 INFO eval.AbstractDifferenceRecommenderEvaluator: Starting timing of 3 tasks in 1 threads
 13/04/12 23:38:18 INFO eval.StatsCallable: Average time per recommendation: 7ms
 13/04/12 23:38:18 INFO eval.StatsCallable: Approximate memory used: 6MB / 31MB
 13/04/12 23:38:18 INFO eval.StatsCallable: Unable to recommend in 2 cases
 13/04/12 23:38:18 INFO eval.AbstractDifferenceRecommenderEvaluator: Evaluation result: 1.0
 1.0

はっきり言って、何の解説も無しにこの結果だけ見てもさっぱりわかりませんw

Mahout本によると、まあ、今回使用したevaluatorは「AverageAbsoluteDifferenceRecommenderEvaluator」で、「レコメンダが推薦するアイテムの推奨値と、実際にユーザがつけた推奨値の差の絶対値の平均を出力する」評価器らしいw

ということは、今回の評価では、レコメンダが計算し推奨値と実際にユーザがつけた推奨値は平均で1.0の誤差があるということになるらしい。

なるほどー。

また、Mahout本では「単純な平均ではなく、二乗平均平方根でもスコアづけできるよ」ってかいてあったのでやってみましたw

「RMSRecommenderEvaluator」っていうEvaluatorを使用するらしい。

して、以下のコードをmainメソッドの最後に追加。
 RecommenderEvaluator evaluator2 = new RMSRecommenderEvaluator();
 double score2 = evaluator2.evaluate(builder,null,model,0.7,1.0);
 System.out.println(score2);

結果はこんな感じです。
 SLF4J: Class path contains multiple SLF4J bindings.
 SLF4J: Found binding in [jar:file:/opt/extend/mahout/Mahout1/lib-mahout/lib/slf4j-jcl-1.6.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
 SLF4J: Found binding in [jar:file:/opt/extend/mahout/Mahout1/lib-mahout/lib/slf4j-log4j12-1.6.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
 SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
 13/04/13 00:05:12 INFO file.FileDataModel: Creating FileDataModel for file data/data1/intro.csv
 13/04/13 00:05:12 INFO file.FileDataModel: Reading file info...
 13/04/13 00:05:12 INFO file.FileDataModel: Read lines: 21
 13/04/13 00:05:12 INFO model.GenericDataModel: Processed 5 users
 13/04/13 00:05:12 INFO eval.AbstractDifferenceRecommenderEvaluator: Beginning evaluation using 0.7 of FileDataModel[dataFile:/opt/extend/mahout/Mahout1/data/data1/intro.csv]
 13/04/13 00:05:12 INFO model.GenericDataModel: Processed 5 users
 13/04/13 00:05:12 INFO eval.AbstractDifferenceRecommenderEvaluator: Beginning evaluation of 3 users
 13/04/13 00:05:12 INFO eval.AbstractDifferenceRecommenderEvaluator: Starting timing of 3 tasks in 1 threads
 13/04/13 00:05:12 INFO eval.StatsCallable: Average time per recommendation: 6ms
 13/04/13 00:05:12 INFO eval.StatsCallable: Approximate memory used: 6MB / 31MB
 13/04/13 00:05:12 INFO eval.StatsCallable: Unable to recommend in 2 cases
 13/04/13 00:05:12 INFO eval.AbstractDifferenceRecommenderEvaluator: Evaluation result: 1.0
 13/04/13 00:05:12 INFO eval.AbstractDifferenceRecommenderEvaluator: Beginning evaluation using 0.7 of FileDataModel[dataFile:/opt/extend/mahout/Mahout1/data/data1/intro.csv]
 1.0
 13/04/13 00:05:12 INFO model.GenericDataModel: Processed 5 users
 13/04/13 00:05:12 INFO eval.AbstractDifferenceRecommenderEvaluator: Beginning evaluation of 3 users
 13/04/13 00:05:12 INFO eval.AbstractDifferenceRecommenderEvaluator: Starting timing of 3 tasks in 1 threads
 13/04/13 00:05:12 INFO eval.StatsCallable: Average time per recommendation: 1ms
 13/04/13 00:05:12 INFO eval.StatsCallable: Approximate memory used: 6MB / 31MB
 13/04/13 00:05:12 INFO eval.StatsCallable: Unable to recommend in 2 cases
 13/04/13 00:05:12 INFO eval.AbstractDifferenceRecommenderEvaluator: Evaluation result: 1.0
 1.0

うーむ、結局、今回のケースではどっちでやっても「1.0」なんだ、、、