低スペックな頭の僕がJavaの機械学習ライブラリmahoutを動かしてみる。

あわせて読みたい
Apache Mahoutで機械学習してみるべ - 都元ダイスケ IT-PRESS

地豆んじゃーリーダーが面白そうなライブラリでエントリあげていたので乗っかってみる。基本的に機械学習がなんたるかとか機械学習の結果を統計学的に云々なんてことはよくわかってないのでその辺はリーダーのエントリをお読みください。

Apache mahoutって何よ?

Apache Mahout:: Scalable machine-learning and data-mining library
スケーラブルな機械学習ライブラリって書いてあります。でも、俺たちの目指すスケーラブルってちょっと違うんだぜ!ともいっています。

  • 巨大なデータに対してスケーラブル
    • Hadoop使っても使わなくても大丈夫だよ!
  • 様々なビジネスに対してスケーラブル
    • Apache Software Licenseで提供するよ!
  • スケーラブルコミュニティ
    • 何かあったらコミュニティで議論しようぜ!まってるぜ!

具体的に何が出来るかというと、データの集合体からレコメンドの抽出とかクラスタリング処理をすることが出来ます。

とりあえず動かしてみる

CSVを取り込んでレコメンドを取得してみます。プロジェクト全体像は以下の通りです。

pom.xml

まずは必要なライブラリの設定。mahout-coreとslf4cldc-nopが必要なのでdependenciesは以下の通りに設定。JDKは1.6以降のみ対応です。切り替えをわすれないように。

  <dependencies>
  	<dependency>
  		<groupId>org.apache.mahout</groupId>
  		<artifactId>mahout-core</artifactId>
  		<version>0.4</version>
  	</dependency>
  	<dependency>
  		<groupId>com.github.mcpat.slf4j</groupId>
  		<artifactId>slf4cldc-nop</artifactId>
  		<version>1.6.0</version>
  	</dependency>
  </dependencies>

取り込むcsv

取り込むcsvはこんな感じです。

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

順にUser、Item、Preferenceです。それぞれユーザーID、アイテムID、評価点(お気に入り度みたいなかんじ)を示しています。それぞれの型定義はUserとItemはlong。PreferenceはFloatで記述します。*1何かのシステムであればこれが売上データであったり、ユーザレビューの結果であったりといった感じです。
ここで適当にデータを作るとオススメデータが何もないという('・ω・`)ショボーンな結果になります。

ソース

レコメンドしてくれるサンプルソースです。

package org.kirino.mahout;

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

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;
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 MahoutSample {

	/**
	 * Mahoutの簡単なサンプル 1番のユーザに対するレコメンドを1つだけ出力します。
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			// データの取り込み
			DataModel dataModel = new FileDataModel(new File(
					"src/main/resources/data.csv"));
			// 相関性の評価基準の設定
			UserSimilarity similarity = new PearsonCorrelationSimilarity(
					dataModel);
			// 評価の近い人を探すロジックを決めてる?
			UserNeighborhood neighborhood = new NearestNUserNeighborhood(3,
					similarity, dataModel);
			// レコメンダの作成
			Recommender recommender = new GenericUserBasedRecommender(
					dataModel, neighborhood, similarity);

			// 1番の人に対するレコメンドが1つ
			List<RecommendedItem> recommendations = recommender.recommend(1, 1);
			for (RecommendedItem recommendation : recommendations) {
				System.out.println(recommendation);
			}

			System.out.println("end");

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (TasteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

解説するよ!

// データの取り込み
DataModel dataModel = new FileDataModel(new File("src/main/resources/data.csv"));

まずはcsvファイルからDataModelを作成します。今回はファイルからの取り込みですが、MySQLから取り込むものやJDBC経由で汎用的にデータを取り込むクラスがあります。この辺はちょっと調べると色々出来るような感じ。

// 相関性の評価基準の設定
UserSimilarity similarity = new PearsonCorrelationSimilarity(dataModel);

類似性の尺度の設定です。PearsonCorrelationSimilarityはアイテム毎のお気に入り度の平均を求めるときに相乗平均を利用するようです。*2他にSpearmanCorrelationSimilarityやTanimotoCoefficientSimilarityなどがあります。それぞれ計算式がことなるようです。

// 評価の近い人を探すロジックを決めてる?
UserNeighborhood neighborhood = new NearestNUserNeighborhood(3,similarity, dataModel);

正直この辺からよくわかってません。アイテムとその評価点の傾向をから似たユーザを探す処理のようです。第一引数が一人のユーザに対して何人の傾向の似ているユーザを探すか指定しています。これくらいのデータだと1に設定すると結果が出ないかも。

// レコメンダの作成
Recommender recommender = new GenericUserBasedRecommender(dataModel, neighborhood, similarity);

データと評価の近い人のデータからレコメンダを作成します。他のレコメンダもあります。

// 1番の人に対するレコメンドが1つ
List<RecommendedItem> recommendations = recommender.recommend(1, 1);

レコメンダからレコメンデーションを取り出します。今回はユーザIDが1に対するレコメンデーションを1つ取り出します。データが多ければきっと2個でも3個でも出るかと思います。今回は1個しかでませんでした。

結果

RecommendedItem[item:106, value:3.9137328]
end

1番の人に対するオススメはアイテム106で評価点は3.9くらいつけるんじゃねーの?とmahoutくんはいってます。オススメできない場合はなにも出力されません。あと評価点が計算できない場合はNaNを返却するらしいです。

まとめ

amazonのオススメとかこういう感じで裏で動いてるみたいです。mahout使ってるかどうかは知りませんが。サイトでJavadocがみれないのはちょっと痛い*3ですけどなかなかおもしろそうです。今回はcsvから取り込みましたがDBからも直接取り込めそうなのでいろいろ出来そうな感じです。はい。

*1:JavaDocをみるとそれぞれの返すメソッドがその型になってる

*2:JavaDocによると

*3:mahoutのサイトでは404になってる。CIもみれない。javadocだけならこちら