Apache Mahout で単純なレコメンドを実施 - Groovy

Groovy で機械学習ライブラリの Apache Mahout を使った単純なレコメンド処理を試してみました。

サンプルソースは http://github.com/fits/try_samples/tree/master/blog/20111113/

レコメンド処理の実装

Apache Mahout の基本的なレコメンド処理は、入力データを抽象化した DataModel をレコメンド処理を抽象化した Recommender に設定して recommend メソッドにレコメンド対象のユーザーIDとレコメンドアイテム数を指定するだけです。

今回は以下のような CSV ファイルを入力データとする FileDataModel と GenericItemBasedRecommender を使ってみました。

入力 CSV ファイルフォーマット
<ユーザーID>,<アイテムID>,<評価値>
・・・

GenericItemBasedRecommender はコンストラクタで指定する Similarity によって類似性の算出方法が切り替えられるようになっています。
Mahout 0.5 には複数の Similarity が用意されています。(以下は一部)

  • UncenteredCosineSimilarity : コサイン類似度
  • EuclideanDistanceSimilarity : ユークリッド距離
  • CityBlockSimilarity : マンハッタン距離
  • PearsonCorrelationSimilarity : ピアソン相関
item_recommend.groovy
@Grab("org.apache.mahout:mahout-core:0.5")
@Grab("org.slf4j:slf4j-jdk14:1.6.3")
//ログ出力を止めたい場合は slf4j-jdk14 をコメント化し以下を有効にする
//@Grab("org.slf4j:slf4j-nop:1.6.3")
import org.apache.mahout.cf.taste.impl.recommender.*
import org.apache.mahout.cf.taste.impl.similarity.*
import org.apache.mahout.cf.taste.impl.model.file.FileDataModel

if (args.length < 2) {
    println "${new File(System.getProperty('script.name')).name} <csv file> <target userID>"
    return
}

//入力データ
def data = new FileDataModel(new File(args[0]))

//コサイン類似度
def similarity = new UncenteredCosineSimilarity(data)
//ユークリッド距離には以下を使う
//def similarity = new EuclideanDistanceSimilarity(data)

def recommender = new GenericItemBasedRecommender(data, similarity)

//レコメンドの実施
recommender.recommend(Long.parseLong(args[1]), 5).each {
    println "result : ${it.itemID}, ${it.value}"
}

ちなみに、SVD(特異値分解)や Slope One 等の本格的なアルゴリズムを使用するには、専用の Recommender(SVDRecommender や SlopeOneRecommender)を使用するようです。

実行

実は、上記を普通に実行しても以下のようなエラーが発生し動作しません。(mahout-core の依存関係の設定に問題がある模様)

実行時エラー
> groovy item_recommend.groovy
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
General error during conversion: Error grabbing Grapes -- [unresolved dependency: com.google.guava#guava;r03: not found, download failed: commons-logging#commons-logging;1.0.3!commons-logging.jar]
java.lang.RuntimeException: Error grabbing Grapes -- [unresolved dependency: com.google.guava#guava;r03: not found, download failed: commons-logging#commons-logging;1.0.3!commons-logging.jar]
・・・


この問題を解決するスマートな方法がわからなかったので、今回は Grape がローカルにダウンロードした mahout-core の ivy.xml (実際は %USERPROFILE%\.groovy\grapes\org.apache.mahout\mahout-core\ivy-0.5.xml ファイル)を直接書き換えて対応しました。

%USERPROFILE%\.groovy\grapes\org.apache.mahout\mahout-core\ivy-0.5.xmlの変更例
<ivy-module version="2.0" xmlns:m="http://ant.apache.org/ivy/maven">
    ・・・
    <dependencies>
        ・・・
        <!-- rev の値を変更(r03 -> 10.0.1) -->
        <override org="com.google.guava" module="guava" matcher="exact" rev="10.0.1"/>
        ・・・
        <!-- commons-logging を追加 -->
        <override org="commons-logging" module="commons-logging" matcher="exact" rev="1.1.1"/>
    </dependencies>
</ivy-module>


とりあえず、これで正常に実行できるようになります。

実行例 (ユーザーID=1 のレコメンドアイテムを出力)
> groovy item_recommend.groovy sample_data.csv 1
11 12, 2011 8:54:25 午後 org.apache.mahout.cf.taste.impl.model.file.FileDataModel <init>
情報: Creating FileDataModel for file sample_data.csv
11 12, 2011 8:54:25 午後 org.apache.mahout.cf.taste.impl.model.file.FileDataModel processFile
情報: Reading file info...
11 12, 2011 8:54:25 午後 org.apache.mahout.cf.taste.impl.model.file.FileDataModel processFile
情報: Read lines: 15
11 12, 2011 8:54:25 午後 org.apache.mahout.cf.taste.impl.model.GenericDataModel <init>
情報: Processed 5 users
result : 4, 3.6666667

アイテムID=4 がレコメンドされたアイテムです。

ちなみに、入力ファイルが以下のように単純すぎたため 1アイテムしか出力されていません。

入力ファイル例
1,1,4
1,2,5
1,3,5
1,5,2
2,1,4
2,2,5
2,4,3
2,5,1
・・・


ある程度の規模の入力データを使うと Similarity による違いが出てなかなか興味深いです。

実行例2(コサイン類似度 UncenteredCosineSimilarity)
> groovy item_recommend.groovy jester_ratings.csv 1
・・・
情報: Processed 59132 users
result : 114, 4.388584
result : 117, 4.3182726
result : 129, 4.2214856
result : 138, 4.219198
result : 148, 4.108847
実行例3(ユークリッド距離 EuclideanDistanceSimilarity)
・・・
情報: Processed 59132 user
result : 149, 2.2220674
result : 143, 2.2179255
result : 133, 2.2131546
result : 137, 2.2050552
result : 145, 2.204735
実行例4(マンハッタン距離 CityBlockSimilarity)
・・・
情報: Processed 59132 users
result : 117, 3.3347886
result : 129, 3.259704
result : 148, 3.1350408
result : 114, 3.1283274
result : 150, 3.1082058