Apache Mahoutの開発環境を作成する。

今回は、Eclipse(Juno)でMahoutの開発環境を作成し、「Mahout in Action」にある協調フィルタリング(リコメンデーション)のサンプルを動かしてみる。

Mahoutイン・アクション

Mahoutイン・アクション

開発機はMac Book Pro (Mountain Lion)、javaは1.6。Mahoutのバージョンは0.8、Hadoopのバージョンは1.1.2。

MacBook-Pro:~ tetsuya$ java -version
java version "1.6.0_51"
Java(TM) SE Runtime Environment (build 1.6.0_51-b11-457-11M4509)
Java HotSpot(TM) 64-Bit Server VM (build 20.51-b01-457, mixed mode)

まず、Javaプロジェクトを作成する。

次にプロジェクトのPropertiesのJava Build Pathに以下の外部jarを設定する。

  • MAHOUT_HOME直下にあるjar
  • MAHOUT_HOME/libの直下にあるjar
  • hadoopをインストールしている場合は、hadoop-core-x.x.x.jar

入力データを入れるために、inputフォルダーを作成し、intro.txtを作成する。
intro.txtは、「Mahout in Action」のP15にあるサンプルである。


データだけ抜き出すと以下のようになる。

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

適当なパッケージを作って、新規にクラスを作成する。

以下がJavaプログラムとなる。

package com.tetsuyaodaka.mahout.samples;

import java.io.File;
import java.io.IOException;
import java.util.List;

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;
import org.apache.mahout.cf.taste.common.TasteException;
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;

public class RecommenderIntro {

	/**
	 * リコメンダーのサンプルプログラム
	 *  Mahout in Action example2-2
	 *  
	 * @throws IOException 
	 * @throws TasteException 
	 */
	public static void main(String[] args) throws IOException, TasteException {

		//DataModelの作成
		DataModel model = new FileDataModel(new File("/Users/tetsuya/Documents/workspace_jee/mahoutsample/input/intro.txt")); // throw IOException
		// 類似性の定義
		UserSimilarity similarity = new PearsonCorrelationSimilarity(model); // throw TasteException

		// N近傍の定義
		UserNeighborhood neighborhood = new NearestNUserNeighborhood(2,similarity,model);

		// 上記のデータモデル、類似性、N近傍を使ったリコメンダーを作成する。
		Recommender recommender = new GenericUserBasedRecommender(model,neighborhood,similarity);
		
		// ユーザー1に1つのアイテムをリコメンドする。
		List<RecommendedItem> recommendations = recommender.recommend(1, 1);
		
		// 結果の出力
		for(RecommendedItem recommendation : recommendations){
			System.out.println(recommendation);
		}
		
	}

}

実行結果は以下。
アイテム104をリコメンドすべきであって、その根拠となる「ユーザー1がアイテム104を評価するときの推定評価」は、4.257081とでる。

RecommendedItem[item:104, value:4.257081]


さて、それではプログラムを少しひも解いてみたい。データを行列の形にかくと、

となる。


これを見る限りユーザー4、5に近く、ユーザー2に遠い。
とすれば、ユーザー4、5の評価が高く、かつ、ユーザー1が見ていないものは、104か106となる。
ユーザー1とユーザー4、5を比較するのには、両方ともに見ている映画だけで評価するのが妥当だろう。そうすると、ユーザー4の方が近くなりそう。すると、ユーザー4が4.5をつけている104がユーザー1にリコメンドされると推測できる。推定値4.25は、ユーザー1が、ユーザー4と5の中間に位置づけられたことを示しているのだろう。
もし、リコメンド数を2にしたら106が2番目にリコメンドされるはずである。
そこで、上のプログラムを以下のように修正して実行してみる。

	// ユーザー1に2つのアイテムをリコメンドする。
	List<RecommendedItem> recommendations = recommender.recommend(1, 2);

すると、予想通り、2番目のレコメンドとして推定されたアイテム106の推定値は4.0。ユーザー4と5の評価と同じ値である。

RecommendedItem[item:104, value:4.257081]
RecommendedItem[item:106, value:4.0]