Apache Mahoutで機械学習してみるべ

では、本文いきます。

Apache Mahoutっていう機械学習ライブラリがあります。詳しくはApache Mahout の紹介辺りを参考にしてください。

まぁ、要するにクラスタリング*1とか、レコメンデーション*2なんかをするクラスライブラリです。

例えばAmazonの「おすすめ」は、大勢のユーザの購買履歴に基づいて、各ユーザが興味を持ちそうな製品を算出しています。また、Facebookの「もしかして、この人と知り合いではありませんか?」というのも、機械学習によるものです。
さらに、Google Newsには次々とニュース記事が入ってきますが、「あるニュースとその続報」など、関連の深いニュースをひとまとめのスレッドにして表示したりしています。この「ニュースの分類」も手動ではなく、本文中に現れる単語の頻度などを分析した結果、自動でまとめています。また、同じ技術を使って、「このメールはスパムか否か」ということも計算で判定できるのです。これはgmail等で利用されています。

そんな中、レコメンデーションエンジンなんかは、様々な言語で色々な実装があり、OSSとして公開されているものも多くあります。そんな中でMahoutが一押しであるのは、スケーラビリティの確保に重点が置かれていることです。

機械学習というのは、当然、計算に基づいて結果を出すわけですが、その基礎となるデータが多ければ多いほど、確からしい結果を出してくれます。が、しかし、データが多ければ多いほど、指数的に計算量が増加する傾向があります。近年、このような大量データ処理のニーズは高まっています。その辺りの考察はHadoopとかに入門してみる 〜 分散技術が出てきた背景 - 都元ダイスケ IT-PRESSを参照。

じゃあHadoopの上で動く機械学習ライブラリを実装すりゃいいじゃん、ていうのがMahoutです。

えぇい、そろそろコード見せろ、って思ってますね? とりあえずレコメンデーションでいきましょう。ひとまずHadoopとかは出て来ません。簡単な感じでいきます。

データを用意する

まず、「基礎となるデータ」を用意します。誰が何をどのくらい好きか、のデータですね。

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

こんなんですね。CSVフォーマットで、user,item,preference という順に並んでます。userとitemはlong型のID、preferenceはfloat型です。ここでは1.0〜5.0の範囲で適当に。5人のユーザと7つのアイテムに登場してもらいました。1番の人は101番のアイテムに5.0点つけました。…(中略)…5番の人は106のアイテムに4.0点をつけました。ってデータですね。

この状況で、1番の人に「新たなアイテム*3」を1つだけお薦めするとしたらどれ? というのがレコメンドです。レコメンデーションエンジンは101〜107のアイテムしか知らないので、104〜107の4択ですが。データ量が多くなれば、もっと幅広く、予想のつかない結果が出て面白いです。

Javaプロジェクトを用意する

Mahoutを使うために、Mavendependencyにコレを入れておきましょう。

<dependency>
  <groupId>org.apache.mahout</groupId>
  <artifactId>mahout-core</artifactId>
  <version>0.4</version>
</dependency>

さっき用意したcsvは、src/main/resources/intro.csv あたりに保存しておきましょう。

コードを書く

DataModel model = new FileDataModel(new File("src/main/resources/intro.csv"));
UserSimilarity similarity = new PearsonCorrelationSimilarity(model);

// 第一引数の意味は明日解説
UserNeighborhood neighborhood = new NearestNUserNeighborhood(2, similarity, model);

Recommender recommender = new GenericUserBasedRecommender(model, neighborhood, similarity);

// 1番の人に対するレコメンドが1つ欲しい、という意味で(1, 1)です。
List<RecommendedItem> recommendations = recommender.recommend(1, 1);
for (RecommendedItem recommendation : recommendations) {
     System.out.println(recommendation);
}

こんだけです! ホントにこんだけです。すげーー。出力結果はこれ。

RecommendedItem[item:104, value:4.257081]

1番の人にお勧めなのは、104のアイテムで、恐らくこの人にこのアイテムを評価させたら4.25点くらいをつけるでしょう。ということです。

*1:データの集合をクラスタと呼ぶグループに分ける。似たようなデータが同じクラスタに属するようになる。

*2:多くのユーザの好みに基づいて、特定ユーザーが興味を持つと思われる情報をお薦めとして提示する。

*3:101〜103は既に知ってるアイテムなのでレコメンドする意味はない。