Apache Mahoutで機械学習してみるべ
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を使うために、Mavenのdependencyにコレを入れておきましょう。
<dependency> <groupId>org.apache.mahout</groupId> <artifactId>mahout-core</artifactId> <version>0.4</version> </dependency>
コードを書く
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点くらいをつけるでしょう。ということです。