Amazon Elastic MapReduceを使う:マネージメント・コンソールからサンプルを動かす。

前回の記事では、Amazon Web ServicesのEMR(Amazon Elastic MapReduce)で、マネージメント・コンソールからクラスタを作成した。
今回は、同じくマネージメント・コンソールから、サンプルプログラム(Word Count)を起動してみる。
Pythonで書かれたサンプルで、詳細はAmazon Web ServicesArticles&Tutorials>Word Count Exampleにある。


クラスタが起動した状態で、マネージメント・コンソールでStepを追加する。

このとき、以下のように設定する。

Step Type Streaming Program(Scriptなので、Hadoop Stremaingを使う)
Name Word Count(任意)
Mapper s3://elasticmapreduce/samples/wordcount/wordSplitter.py
Reducer aggregate
Input S3 Location s3://elasticmapreduce/samples/wordcount/input/
Output S3 Location 結果を出力したいバケット/フォルダー

上図の青いAddボタンを押すと、Stepが追加され、プログラムが実行される。正常に実行されると、下図のように緑でRunning表示される。実行途中、もしくは起動に失敗すると、赤でFailedと表示される。

先の記事で、クラスタのログの出力先を指定した。指定したバケット/フォルダー下のステップ番号(下の例では6)配下に、ログた出力される。

以下が、syslog。

以下がcontrollerログの中身。


StepがCompletedとなったら、ステップ終了。

出力先に指定したバケット/フォルダーに結果が出力される。_SUCCESSは正常終了。part-00000, part-00001, part-00002がワードカウントの結果。

以下が、part-00000の中身である。


一旦ここで、クラスタを終了する。(前回の記事の方法で起動した場合、明示的にクラスタを終了しなければ、クラスタが起動しつづけてしまい、その間、下記されてしまう)
コンソール画面で、Terminateボタンを押すと、以下の画面となる。

これは、クラスタを起動した際に、Termination ProtectionをYesにしたため(下図)。
上の画面で、Changeをクリックして、Protectionを解除する。

すると、ProtectionがOffに変化する。

Terminateを押すと、クラスタが終了し、マネージメント・コンソールにTerminatingと表示される。

Hadoop、おしさしぶり(It's long time to see, Hadoop.)

先日、学会の発表を聞いていて、久しぶりにHadoop+MapReduceをやってみようという気になった。
気がついてみると、昨年の6月〜7月にHadoop+MapReduceの評価をやっていたので、1年ぶりとなる。

1年も経てば、さぞかし変わってしまっているだろうと思っていたのだが、やっぱり変わっていた。

Amazon Web Serviceで、アカウントコンソールからEMR(Elastic MapReduce)を選ぶと、以下の画面が現れた。なぜが、自分のアカウントは、Regionがus-west(Oregon)になってしまう。us-standard(N. Virginia、us-east)に変更する。

いきなり「Create Cluster」にいくのも良くないと思うので、Over Viewのリンクをクリックしてみると、昨年見慣れた画面が現れた。
スクリーンショットが分割してしまうが、このページを見れば大体のことは分かりそう。

スクロールすると、面白そうな事例やゲノムデータが使えますと言った魅力的な文言が見える(ゲノムのページをクリックすると、英語のページに遷移するが、何やら本当にデータを使えるみたい)。

その下にいくと、簡単な使い方が書いてある。こんな説明あったんだ的に読む。「大量のデータを送るには、AWS Import/Export」と書いてある。昨年、一連の実験をしたときに、S3にデータを送るのに相当の時間がかかってしまっていた。これじゃぁ、計算が早くなっても的だったので、今回は使ってみようと思う。

ページの左ペインのメニューにプライスがあるので覗いておく。安くなりこそすれ、高くなってるはずはないだろう。

昨年同様、価格システムは、EC2料金+EMR料金となっている。昨年かなり回してみたが、お小遣いの範囲でいけたので、今年も大丈夫でしょう。

次回から、新しい管理画面の使い方とか、昨年のサンプルなど使って実験をします。

Amazon Elastic MapReduceを使う:マネージメント・コンソールからのクラスタの起動

Amazon Web ServicesのEMR(Amazon Elastic MapReduce)を、マネージメント・コンソールから一通り動かしてみる。
最初の画面(下)で「Create Cluster(青いボタン)」をクリックする。

すると、クラスタをコンンフィギュレーションする画面に切り替わるので、ここで定義していく。以前は、ステップ・バイ・ステップで定義していく形式だったが、1つの画面にまとめられたようだ。

Cluster Nameを適当に入れ、LoggingをS3上にする(「Yes」の場合、「log folder s3 location」にlogを保管したいS3バケットとフォルダーを指定する。入力フィールド右のフォルダー・アイコンをクリックすると自分の持っているバケットの一覧が表示されて、フォルダーまで選択できるようになっている)。
Termination Protectionは、終了時の保護機能のようで、これをYesにしておくと、クラスタを終了するときに、Protectionを外さなくてはならなくなる(後述)。
また、クラスタを識別するためのタグ(任意)を入力できる。何かと思って説明をよむと、たんなる識別子のようだ。
AMI(Amazon Machine Image)の選択をみると、EMRでデフォルトで提供されているMachine ImageのHadoopのバージョンは1.0.3となっている。(選択肢としては、0.20から2.4.0まで選択可能)

下にスクロールすると、

pigとhiveを配備するかどうか、他のアプリを配備するか指定できる。デフォルトでpigのバージョン0.11、hiveの0.11が配備される。(これらは、クラスタ起動時にステップとして配備される)
Hardware Configurationでは、VPC(Virtual Private Cloud)を使うかどうかを設定する。自分の場合、VPCを使う理由はないので、デフォルトのままにしておく。Zoneもここで選択可能。自分の場合は、us-standard(N.Virginia)でテストする。
その下がクラスタ構成となっていて、デフォルトではmasterとしてm1.smallが1インスタンス、coreが2インスタンス、taskが0インスタンス。coreはName NodeとJob Tracker、taskではJob Trackerのみが動く。Spot Requestをする場合には、右にチェックをいれる。
Secutity And Accessでは、SSHで使うアクセスキーを指定する。昨年試用していたキーを指定した。
IAMとは、Amazon Identify And Access Managementの略。

さらに下にスクロールすると、

Bootstrap Action(EMRインスタンスの初期設定)とStepの定義ができる。
ステップは後で追加するのでこのままにしておく。
Auto Terminateは、デフォルトのままNoにしておく。この状態だと、Stepの起動・終了と、クラスタの起動・終了が切り離されるので、クラスタを明示的にTerminateしなくてはならない(ずっと、課金されてしまう)

ここまで入力したら、Create Clusterボタンを押して、クラスタを起動する。クラスタの管理画面に遷移する。

上は、先に定義した内容でクラスタが起動中の状態。Cluster(クラスター名:My Cluster)のステータスはStarting、インスタンスのステータスはprovisioningと。まだ、masterノードが起動していないので、master public DNSのところには何も記載されていない。(Job IDは取得されて、Summaryのところ表示される)。

Monitorを展開すると、Cluster、MapReduce他のステータスがグラフで見られるようになっている。(詳細な内容はここでは確認できないが、Slot数などは見られる)

Stepsを展開すると、初期化ステップとして、Hadoop環境のセットアップ、(先にデフォルトで指定されていた)pigとhiveのセットアップがStepとして動いていることが確認できる。Stepのログもこの画面から確認できるようになっている。

しばらく待つと、セットアップが完了し、以下のような画面となる。Cluster、HardwareのステータスがRunningとなり、クラスタの構成は完了。masterのpublic DNSが画面に表示されるようになったのは、あとあと便利。以前は、EC2の画面から調べていて、ノード数が増えてくると面倒だった。

ここまでくると、とりあえずは、ステップを追加してジョブを流すことができる。

次回の記事: Amazon Elastic MapReduceを使う:マネージメント・コンソールからのサンプルを動かす。

迷惑メールの基礎知識

最近、相談を受けることが増えたこともあって、迷惑メールが増えているのかな、と思って調べてみました。
シマンテック2013/1のインテリジェンスレポート(2013/1の1ヶ月分)をみると、メールの全流量に占めるスパムメールの割合は64.1%。半年の平均が70.4%とのこと。

そのうちの71.65%が「Sex/Dating(出会い系みたいな奴)」に分類されています。メイルボックスに落ちてくるスパムの大半はこれですよね。

え!?と感じられる方も多いのではないかと思うのですが、もう随分昔から「メール全体の70-80%はスパムメール」というのが常態化しているのです。

フィッシングメイルは、508通に1通、ウィルスメールは400通に1通の割合とのこと。

スパムに話を戻すと、基本的に「どんなメールサービスも少なくともスパム対策を施している(自社でメールサーバーを運用している場合を除く)」ということが、この統計から分かると思います。そうでなければ、迷惑メールの方が多くなってしまいます。

ここで問題となるのは、どれだけ多くのスパムをフィルター(防御するソフトウェア)が検出できるか、という点。

スパムをブロックするためには、怪しいアドレスをデータベース化するとか、ドメインを偽装していないかとか、という古典的な防御手法の他にも、通信流量が極端に多くないかとか、パケット内のデータパターンが怪しくないか、キーワードの組み合わせからリスクを分析するとか、最新の先端技術が使われています。(古いですけど、こちらのITプロの記事がは分かりやすいです)

そして、先に挙げた怪しいアドレスや、パターン、キーワードの組み合わせなどは、膨大なデータベースを元にしているので、メールサービスを提供する企業やセキュリティーソフトウェアの供給企業の競争優位の源泉となっています(もちろん公的なものもあります)。

昔、GoogleGmailを初めて使った際に驚いたのは、容量(当時、数10Mが普通だったところに2GBというメイルボックスを提供した)よりも、スパムブロックの精度でした。これを無料で使っていいのですか?、と。

Googleとか、Microsoftとか、巨大なデータを素早く扱うことができる企業のみが、こういったサービスを提供できるわけで、それでも100%ということは理屈的にはありえません。
自前でメールボックスを持とうとすると、最低でも7桁のオーダーの投資が必要になります。(それだけ投資をしても、Gmailのように、各人に15GBとかのボックスをあてがうことはできません)

電子メールはとても便利なシステムですし、社会的インフラとしての地位も確立しています。
これを思うと、スパム対策されたメールシステムが、無料とか、月額数百円で使える時代になったということは素晴らしいこと。法人向けクラウドサービスの場合、もうすこし値段がかかりますが、10年前の状況とは隔世の感があります。


それとともに、「スパムとの戦い」は、インターネットでメールがやり取りされる限り、「永遠の戦い」であって、スパムがメイルボックスに落ちてくるのは、原理的に「ある程度は仕方がない」こと。
というのも、スパムメールのフィルタリングは「諸刃の剣」で、「ルールが厳しすぎると必要なメールがスパム」になってしまいます。Gmailのメイルボックスをみると、結構、必要なメイルが迷惑メールに分類されていて驚いたりします。たとえば、メルマガを運用したい場合、同一アドレスから大量のメールが発生しますが、これは(流量面からみれば)スパムメールと同じ挙動です(「出来るだけ多くの人に読んでもらいたい」という願いは、スパムを送る人間にとっても同じこと)。

個人としてできることは、迷惑メール通報や迷惑メールアドレス・ドメインの登録をすること(これらの情報は共有されます)、メイラー(メイルソフト)に学習させる、といったことで、これらの積み重ねが「複合的な防御」になって機能します。

NTTドコモがビッグデータを売り出したインパクト:解説

読売新聞の朝刊(2013年9月13日)の経済面に「ドコモのビッグデータ どう使う?」という記事が出た。以下は抜粋。

国内最大の携帯電話会社、NTTドコモは、携帯電話利用者の位置情報などがわかるビッグデータ(人口情報)を10月から販売する。新たな経済活動な災害時の情報提供などの様々な分野での活用が期待される。
Q どうやって人の位置情報を集めるのか?
A 携帯電話の基地局は、通信状況を確認するために、エリア内にどの携帯電話があるかを常に把握している。
例えば、あるエリアにドコモの契約者が15人いたとすると、携帯電話事情におけるドコモの占有率は半数弱なので、エリア内におおよそ30人いたと推測できる。
... (略)
「○日午前8時台、東京駅周辺に50歳代男性が○人いた。そのうち○人は都外の居住者」という情報が得られる。ドコモは顧客企業の要望に合わせて必要な情報を販売する。
Q どういう利用方法が考えられるのか。
A ある地域の時間帯ごとの年代別、性別ごとの人の動きを変化が分かれば、飲食店はそれにあわせて、仕入れる材料の量や種類を調達できる。小売店の出店計画も立てやすくなる(※1)。
地方自治体は、防災計画の策定やまちづくりに生かせる。ドコモは仙台市と共同で、災害時の帰宅困難者の推計調査を行った(※2)。
... (略)
ドコモは契約者が電話で申請すれば、その人のデータの利用を停止する(※3)。

... 読売新聞 2013年9月13日(金曜日)朝刊8面より抜粋。※は筆者による。


以前、「JR東日本がSuica情報を売り出したことと、Hadoop MapReduceの実力(2013/7/18)」というログで簡単なシミュレーションを使って、JR東日本Suica情報を売り出したことの意味について説明した。

それから、ほぼ2ヶ月で「本命」のビッグデータの販売が開始される。

ドコモのこの商材については「1冊でわかるビックデータ・・・ビジネス革命の新潮流(2012/7:日経BP)」に記載がされている。この本には、技術的な内容も書かれているが、読み物としても面白いし、Mook本なので読みやすい。出版されてから、1年で状況がどんどん変わってしまっているが、それはこの業界の常。読んでみられてはいかがかと思う。

1冊でわかるビッグデータ (日経BPムック)

1冊でわかるビッグデータ (日経BPムック)

さて、上の本で知ったのだが、この商材は「モーバイル空間統計(ドコモのホームページに説明があります)」という東京大学との2010年からのプロジェクトが発端になっているようだ。
携帯アプリの開発者の目から見ると、携帯の位置情報を知るには、(しばらく前のようにGPSが搭載されていない端末が多かった頃には)「今、どこの基地局を使っているか」という情報を利用していた。GPSが搭載される携帯電話が普及しても、(やはり、搭載していない携帯はあるので)、GPS基地局情報の2段構えで、携帯の場所を特定させるアプリを作っていた。こういったアプリは、最近作っていないが、顧客ニーズによっては、GPSのみでいい、という時代になっているかもしれない。ただ、GPS情報は、(機密的に)数メートルから数十メートルの誤差が出るような仕組みになっているので、カーナビなどはセンサーでそれを補正している(最近のスマホには、加速度センサーが着いているので、Googleのナビなどは当然、スマホ(アンドロイド)の加速度センサーで位置を補正しているはずである。

話が脇道にそれてしまったが、携帯電話で場所を特定する方法として、「全ての携帯をカバーする」という意味で「一番近く(=携帯と通信する)基地局」を使うのは、ある意味で常識的手段である。

そして、上記のインフラを使って、※2の「災害時の帰宅困難者の予測(と施策)」を行ったのは、工学院大学との共同プロジェクトと(上記の本には)記載されている。

さて、上記の本によると、(その時点の)携帯電話の台数は6000万台、これらが、1時間ごとに一番近い基地局と通信しているとのこと。
ドコモのホームページから基地局の数を調べてみると、2011年時点で9万5000カ所。(通話品質競争が激しいので、増えていることはあっても、減っていることはないと思われる)。
ちなみに、気象庁のホームページをみると、全国の地震観測点は4200カ所だから、計測点としてはその20倍以上もある。
上記の本によれば、モーバイル空間統計では、500メートルから1キロメートル四方のメッシュ内での人口分布(人数、性別、年齢層)が把握できる、という。

以下は、上の記事をイメージしやすく図にしたもの。グラフの高さが人口を表すが、実際のデータに基づいていません(あくまでイメージ)。
上は、昼間の人口分布、下が夜間の人口分布。きっと、こんな具合になるのでしょうね。


これに、性別という属性をつけたら以下のようなイメージになる。ここでも、上は、昼間の人口分布、下が夜間の人口分布。

ここで、想像力を働かせて、上のグラフのメッシュは1キロ程度四方であること、1時間おきの観測結果が時系列で取得できること、性別以外にも、年齢や居住地といった情報が取得できること、をイメージすると、※1で言っていることの意味(以前のログで解説したのとおなじ帰結)がハッキリと「スゴい!!」と理解できると思う。
JR東日本Suicaデータが東日本に限られているのに対して、NTTドコモは全国版のデータになっている。しかも、電車が主たる交通手段ではない地域(こういった地域の方が圧倒的に多い)もカバーできる。
郊外型のホームセンターなどの小売り大手がこれの情報を買わないはずがない、と納得してしまう。応用範囲を考えると、夢が広がっていく。先ほど「本命のビッグデータ」と書いたのはそういう意味である。


このログでは、ビジネスへのインパクトを考えてきたが、当然、個人情報保護面でのセーフガードは必要で、それについては、NTTドコモのホームページ(先のリンク先など)に匿名化や方法が記載されている。
上に紹介した本で「モーバイル空間統計」を知った際に一番驚いたのが、「携帯が自動的に基地局と通信しているのを知らなかった」こと。これはいいのだろうかな、と思った。
総務省のホームページを調べてみると、「法令上は、第三世代携帯電話に対して、発信場所または基地局の位置情報を通知することが義務化されており」と書いてありましたから、携帯と基地局の通信は、法制化されているのですね。GPSの搭載の義務はありませんが、将来的にはあり得ますよね(2007年近辺で盛り上がってたように、Webでは見えます)


いずれにしても、ここでも問題視すべきなのは、今後、このようにどんどん強化されていく情報武装によって、大手と中小の間で「すでにあるギャップが加速的に大きくなる」だろうこと。
情報にも「公共性」という概念があるはずだし、「帰宅困難者や、首都直下型地震の被害規模の予測」といった問題は「公共的」な課題。こういうことは議論すべきだし、広く告知されるべきと思う。

30分でできる分散レコメンデーション:パラメータを変更して、応用できるようにする。

仕事が忙しくて、更新に間があいてしまった。

前々回前回のログApache Mahout0.7で実装されている「Parallel ALS (Parallel Alternating Least Squares)アルゴリズム」をつかって、とても簡便にスケーラブルなリコメンデーションエンジンを構築してみた。
実行には、Amazon Elastic MapReduceのm1.mediumのインスタンスを使用した。Mahoutに付属するサンプルジョブは、m1.smallでも実行できるが、Hadoopの実行要件を考えれば、m1.medium以上で実行するのが適当。実際、「30分で構築するレコメンデーションエンジン」で利用したLibisetiデータのスケールでは、m1.smallを使うと、Heapが不足してジョブがエラーになってしまう。

さて、Libisetiのデータでは、λの値として0.20を選択しており、その選択の根拠を前回のログでは記載した。

今回は、連載の最後として、例示したサンプルをカスタマイズする方法を記しておこうとおもう。


実際に、「30分で構築するレコメンデーションエンジン」のジョブは、以下の要件さえみたせば、全く違ったデータに活用できる。ジョブもスケーラブルに実行されるので、データ量による束縛もない。

  • プリファレンスデータが、「ユーザーID(数値),アイテムID(数値),プリファレンス値(数値)」のフォーマットのCSV形式であること。

上の要件は、Mahoutの協調フィルタリングで利用される「標準フォーマット」であればよい、ということ。データの量や密度(ユーザー×アイテムの行列に対して、どの程度のプリファレンス値が与えられているのか)によって、実行時間や、Hadoopクラスタのスケールが決まってくるが、基本的には上記の1つの要件さえ満たせばいいのは、協調フィルタリングの最大のメリット。しかも、スケーラブルなので、試してみない手はない、といった代物だと思う。

要件は1つだけ、と言ったばかりだが、実際のケースでは、以下のようにジョブ(以下のfactorize-libimseti.sh)を修正する必要がある。

  1. 適切なλを決定する。
  2. 適切なFeature数を決定する。
  3. シェルにハードコードされている、プリファレンス値の上限値を変更する。
if [ "$1" = "--help" ] || [ "$1" = "--?" ]; then
  echo "This script runs the Alternating Least Squares Recommender on the Groupl
ens data set (size 1M)."
  echo "Syntax: $0 /path/to/ratings.dat\n"
  exit
fi

if [ $# -ne 1 ]
then
  echo -e "\nYou have to download the libimseti dataset from http://www.occamslab.com/petricek/data/  before"
  echo -e "you can run this example. After that extract it and supply the path to the ratings.dat file.\n"
  echo -e "Syntax: $0 /path/to/ratings.dat\n"
  exit -1
fi

MAHOUT="../../bin/mahout"
hadoop fs -mkdir /usr/hadoop/tmp/libimseti
hadoop fs -copyFromLocal $1 /usr/hadoop/tmp/libimseti
WORK_DIR=/usr/hadoop/tmp

# create a 90% percent training set and a 10% probe set
$MAHOUT splitDataset --input ${WORK_DIR}/libimseti/ratings.dat --output ${WORK_DIR}/dataset  --trainingPercentage 0.9 --probePercentage 0.1 --tempDir ${WORK_DIR}/dataset/tmp

# run distributed ALS-WR to factorize the rating matrix defined by the training 
set
$MAHOUT parallelALS --input ${WORK_DIR}/dataset/trainingSet/ --output ${WORK_DIR}/als/out  --tempDir ${WORK_DIR}/als/tmp --numFeatures 20 --numIterations 10 --lambda 0.200

# compute predictions against the probe set, measure the error
$MAHOUT evaluateFactorization --input ${WORK_DIR}/dataset/probeSet/ --output ${WORK_DIR}/als/rmse/  --userFeatures ${WORK_DIR}/als/out/U/ --itemFeatures ${WORK_DIR}/als/out/M/ --tempDir ${WORK_DIR}/als/tmp 

# compute recommendations
$MAHOUT recommendfactorized --input ${WORK_DIR}/als/out/userRatings/ --output ${WORK_DIR}/recommendations/ --userFeatures ${WORK_DIR}/als/out/U/ --itemFeatures ${WORK_DIR}/als/out/M/  --numRecommendations 6 --maxRating 10

# print the error
echo -e "\nRMSE is:\n"
hadoop fs -copyToLocal /usr/hadoop/tmp/als/rmse/rmse.txt .
cat rmse.txt
#cat ${WORK_DIR}/als/rmse/rmse.txt
echo -e "\n"

echo -e "\nSample recommendations:\n"

hadoop fs -copyToLocal /usr/hadoop/tmp/recommendations/part-m-00000 .
shuf part-m-00000 |head
#shuf ${WORK_DIR}/recommendations/part-m-00000 |head
echo -e "\n\n"

echo "removing work directory"
rm -rf ${WORK_DIR}

適切なλを決定する。

Prallel ALSの原論文「Large-scale Parallel Collaborative Filtering for the Netflix Prize」では、(Netflix Prizeのデータを使った場合)λ=0.065が最適な値、と記されている。Mahoutに付属する(1MBのMovie Lensデータを使った)サンプルでも、λの値は0.065に設定されている。
だが、先のログで示したように、Libisetiのデータでは、繰り返し実験を行うことで、0.2を最適値としt採用した。このように、実際の現場では、λの値を実験により決定することが必要となってくる。この場合には、Hadoopのマスタノードにログインして、以下のようにして「作成済みのデータを消し」、λの値を変えて再度ジョブを実行すればよい。

rm -fr part-m-00000 
rm -fr rmse.txt
hadoop fs -rmr /usr/hadoop/tmp/*

λは、factorize-libimseti.shにある「--lambda 」の値を書き換えればよい。

# run distributed ALS-WR to factorize the rating matrix defined by the training 
set
$MAHOUT parallelALS --input ${WORK_DIR}/dataset/trainingSet/ --output ${WORK_DIR}/als/out  --tempDir ${WORK_DIR}/als/tmp --numFeatures 20 --numIterations 10 --lambda 0.200

適切なFeature数を決定する。

Feature数もパラメータの1つで、これも適切に設定する必要がある。
この際に注意することは、Featuresのサイズは「スケーラブルではない計算アルゴリズム」によって行われる「行列積と逆行列計算の実行時間」に直接的に影響を及ぼしてしまうこと。これについても、以前のログに記載したが、行列積の算術演算の回数は(仮に正方行列同士の演算と仮定すると)行数(=列数)の3乗のオーダーとなる。Featuresのサイズは、この行数にあたるので、20を30にすると、1.5^3=3.375倍の演算が必要となる。
先のログに示したように、Libisetiのデータでは、featuresの数を30にすることで、逆にRMSEの値が悪くなった。featuresのサイズは「潜在的な変数」的にもとらえられるが、大きくすれば良い結果がでるというものでもないし、演算回数(実行時間)との兼ね合いも含めて吟味する必要がある。

これを変更する場合には、factorize-libimseti.shにある「--numFeatures 」の値を書き換えればよい。

# run distributed ALS-WR to factorize the rating matrix defined by the training 
set
$MAHOUT parallelALS --input ${WORK_DIR}/dataset/trainingSet/ --output ${WORK_DIR}/als/out  --tempDir ${WORK_DIR}/als/tmp --numFeatures 20 --numIterations 10 --lambda 0.200

シェルにハードコードされている、プリファレンス値の上限値を変更する。

これは「プリファレンスの上限値はいくつか」を明示するパラメータで、actorize-libimseti.shにある「--maxRating」の値を書き換えればよい。Libisetiのデータでは最高の評価が10なので、10と設定するが、Movie Lensのように5が最大値なら5と設定する。

$MAHOUT recommendfactorized --input ${WORK_DIR}/als/out/userRatings/ --output ${WORK_DIR}/recommendations/ --userFeatures ${WORK_DIR}/als/out/U/ --itemFeatures ${WORK_DIR}/als/out/M/  --numRecommendations 6 --maxRating 10


さて、なんで「評価の最大値なんて設定するのだろう?」と思わなかっただろうか? この値は、レコメンドの推定に関係する。Parallel ALSでは、以前のログ「Apache Mahoutの分散次元縮約(Parallel ALS)を解説しよう」に記載したように、以下の式によってプリファレンス(レーティング)値を推定する(ジョブの中で10%のトレーニングをつかってRMSEを算出する際にもこの式が用いられる)。

この際、推定されたプリファレンス値が10を超える可能性がある。ここで指定する10という数字は、推定したプリファレンス値が10を超えたら(形式上)10にするよ、という目的で設定する。


さぁ、これで、データを準備すれば自前でレコメンデーションエンジンが構築できると思う。
くどい感は否めないが、MahoutのParallel ALSをこのように応用することで、

  1. 協調フィルタリングによる幅広い応用(上記の形式のデータがあればよい)
  2. スケーラブルなレコメンデーションエンジンの構築(分散処理されるために、1億件のデータがあっても処理できるだろう)
  3. Amazon Elastic MapReduceを使った「自前でサーバーを持たない」ローコスト運用

が可能になる。

30分でできる分散レコメンデーション:パラメータを決定する。

先のログでは、Parallel ALS(Alternating Least Squares)による分散レコメンデーション環境を手っ取り早く用意して、チェコスロバキアの「Libimseti.czという出会い系サイト(http://www.libimseti.cz/)」の1700万件の評価データで、分散レコメンデーションを実行した。

Mahoutでの、Parallel ALSの実装には、2つのパラメータ(λと、フィーチャーの数)がある。実行用に用意したShellでは、λ=0.20、フィーチャーの数を20とした。これは、この2つのパラメータを変えて、簡単なシミュレーションをした結果から決定した。

Featuresの数

フィーチャーの数を20と50にし、RMSEを比較したところ以下の結果を得た。


フィーチャーの数は、縮約する次元を表しており、一見、多いほうがよい精度を得られるように感じられる。反面、以前のログに示したように、フィーチャーの次元は「行列積演算」と「掃出し法による逆行列計算」を単一ノードで動かす次数を意味しており、これを増やすことでフィーチャー数の3乗以上のオーダーで演算回数が増加する。
上の結果をみると、直感に反して、20の方がよい予測精度となっており、かつ、演算速度も速い。よって、フィーチャー数は20とした。

λの値

Mahoutで提供されているサンプル(factorize-movielens-1M.sh)では、λ=0.065とされており、この値は、原論文「Large-scale Parallel Collaborative Filtering for the Netflix Prize」でNetflix Prizeデータを使った場合の最適値である。
今回のサンプルデータで実験したところ、以下の結果を得た。

RMSEの評価

Mahoutイン・アクションの中で、Libimsetiのデータがユーザーベース・レコメンデーション、アイテムベース・レコメンデーション、Slope Oneレコメンデーションの3通りの方法で評価されている。
そこから引用すると、

  • ユーザーベースのレコメンダー(距離尺度=ユークリッド距離、近傍=2):平均絶対誤差=1.12
  • アイテムベースのレコメンダー(距離尺度=Pearsonの相関係数):平均絶対誤差=2.32
  • Slope Oneレコメンダー:平均絶対誤差=1.41

という精度が得られるとのこと。

これらは分散レコメンデーションではなく、1つのマシンで実行された結果であって、平均絶対誤差で評価されている。
これに対して、Parallel ALSは分散レコメンデーション・エンジンである。RMSEの方が、平均絶対誤差よりも大きくでることを考えれば、他の結果に見劣りしない結果と言えるだろう。

Mahoutイン・アクション

Mahoutイン・アクション