Amazon Personalize Web-APIで情報推薦サービスを実現する(6)

AWS

2019.8.1

Topics

今までの記事では、次のような内容を説明してきました。

この記事では、学習に用いた映画評価データに含まれるユーザーや映画のデータを分析し、Amazon Personalizeがどのような情報を推薦してくれるのかを確認しようと思います。

推薦情報を得る

この記事の第4回では、ユーザーと映画のデータをWeb-APIで送信しました。オススメ情報を得るには、ユーザーを識別するIDをWeb-APIに送信し、そのユーザーにおすすめする映画情報のIDを取得します。
そのためのメソッドは、次のように定義できます。

def GetRecommendations(campaignArn, userId)
  endpoint = "https://personalize-runtime.#{REGION}.amazonaws.com/recommendations"
  post_data = {'campaignArn' => campaignArn,
                'userId' => userId}.to_json
  call(endpoint, 'AmazonPersonalizeRuntime.GetRecommendations', post_data)
end

APIのendpointが他のメソッドのものと異なるアドレスであることに注意して下さい。

オススメ情報を得るには、前回の記事で得られたキャンペーンARNと、オススメしたいユーザーのIDを引数としてGetRecommendationsメソッドを呼びます。ここでは「1」という文字列をユーザー識別IDとして渡し、ユーザー1さんへのオススメ映画情報を取得しようと思います。

GetRecommendations('arn:aws:personalize:ap-northeast-1:123456:campaign/sample-campaign', '1')

{"itemList":
         [
           {
             "itemId":"47099"
           },
           {
             "itemId":"136864"
           },
           {
             "itemId":"96079"
           },
(中略)
         ]
}

このユーザー1さんにオススメされた映画は何なんでしょうか?
ここからは、spark-shellを使ってデータの中身を見てみます。

scala> val ratings = spark.read.option("header", "true").option("inferSchema", "true") .csv("file:///tmp/ml-latest-small/ratings.csv")
ratings: org.apache.spark.sql.DataFrame = [userId: int, itemId: int ... 3 more fields]
scala> val movies = spark.read.option("header", "true").option("inferSchema", "true") .csv("file:///tmp/ml-latest-small/movies.csv")
movies: org.apache.spark.sql.DataFrame = [movieId: int, title: string ... 1 more field]
scala> movies.filter("movieId in (47099, 136864, 96079)").select($"movieId", $"title", $"genres").show(false)
+-------+-----------------------------------------+-------------------------------+
|movieId|title                                    |genres                         |
+-------+-----------------------------------------+-------------------------------+
|47099  |Pursuit of Happyness, The (2006)         |Drama                          |
|96079  |Skyfall (2012)                           |Action|Adventure|Thriller|IMAX |
|136864 |Batman v Superman: Dawn of Justice (2016)|Action|Adventure|Fantasy|Sci-Fi|
+-------+-----------------------------------------+-------------------------------+

「幸せの力」「007 スカイフォール」「バットマン vs スーパーマン ジャスティスの誕生」などのようです。ジャンルとしては、ドラマ、アクション、アドベンチャー、スリラーなどとなっています。これらの映画を、ユーザー1さんは喜んでくれるのでしょうか?ユーザー1さんはどんな人なのでしょう。

scala> ratings.filter("userId = 1").join(movies, "movieId").select($"movieId", $"title", $"genres", $"ratings", from_unixtime($"timestamp") as "datetime").sort($"ratings".desc).show(10)
+-------+--------------------+--------------------+-------+-------------------+
|movieId|               title|              genres|ratings|           datetime|
+-------+--------------------+--------------------+-------+-------------------+
|    216|Billy Madison (1995)|              Comedy|    5.0|2000-07-31 03:20:08|
|    457|Fugitive, The (1993)|            Thriller|    5.0|2000-07-31 03:31:49|
|    231|Dumb & Dumber (Du...|    Adventure|Comedy|    5.0|2000-07-31 03:19:39|
|    157|Canadian Bacon (1...|          Comedy|War|    5.0|2000-07-31 04:08:20|
|    163|    Desperado (1995)|Action|Romance|We...|    5.0|2000-07-31 04:00:50|
|     47|Seven (a.k.a. Se7...|    Mystery|Thriller|    5.0|2000-07-31 04:03:35|
|    260|Star Wars: Episod...|Action|Adventure|...|    5.0|2000-07-31 03:28:00|
|    101|Bottle Rocket (1996)|Adventure|Comedy|...|    5.0|2000-07-31 03:14:28|
|    333|    Tommy Boy (1995)|              Comedy|    5.0|2000-07-31 03:19:39|
|    362|Jungle Book, The ...|Adventure|Childre...|    5.0|2000-07-31 03:43:08|
+-------+--------------------+--------------------+-------+-------------------+
only showing top 10 rows

ジャンルで言うと、コメディ、スリラー、アドベンチャー、アクションなどに高得点の評価を付けていますので、確かに喜んでくれそうです。なお、ユーザー1さんは上記のように西暦2000年くらいのデータしかありませんので、西暦2016年のバットマンを見たかどうかは分かりません。

それでは、他に「バットマン vs スーパーマン ジャスティスの誕生」に高得点の評価を付けている人はいるのでしょうか?

scala> ratings.join(movies.filter("movieId == 136864"), "movieId").select($"userId", $"title", $"genres", $"ratings").sort($"ratings".desc).show
+------+--------------------+--------------------+-------+
|userId|               title|              genres|ratings|
+------+--------------------+--------------------+-------+
|   319|Batman v Superman...|Action|Adventure|...|    4.5|
|    62|Batman v Superman...|Action|Adventure|...|    4.0|
|   610|Batman v Superman...|Action|Adventure|...|    3.5|
|   596|Batman v Superman...|Action|Adventure|...|    3.0|
|   125|Batman v Superman...|Action|Adventure|...|    2.5|
|   247|Batman v Superman...|Action|Adventure|...|    2.5|
|   514|Batman v Superman...|Action|Adventure|...|    2.5|
|   305|Batman v Superman...|Action|Adventure|...|    2.0|
|   380|Batman v Superman...|Action|Adventure|...|    2.0|
|   561|Batman v Superman...|Action|Adventure|...|    2.0|
|   448|Batman v Superman...|Action|Adventure|...|    2.0|
|   184|Batman v Superman...|Action|Adventure|...|    2.0|
|    50|Batman v Superman...|Action|Adventure|...|    1.5|
|   534|Batman v Superman...|Action|Adventure|...|    1.5|
|   567|Batman v Superman...|Action|Adventure|...|    1.5|
|    41|Batman v Superman...|Action|Adventure|...|    0.5|
+------+--------------------+--------------------+-------+

たくさんいるようなので、最高得点の4.5を付けているユーザー319さんがどんな人かを見てみましょう。

scala> ratings.filter("userId = 319").join(movies, "movieId").select($"movieId", $"title", $"genres", $"ratings", from_unixtime($"timestamp") as "datetime").show(10)
+-------+--------------------+--------------------+-------+-------------------+
|movieId|               title|              genres|ratings|           datetime|
+-------+--------------------+--------------------+-------+-------------------+
|    110|   Braveheart (1995)|    Action|Drama|War|    4.5|2016-04-23 04:01:52|
|    293|Léon: The Profess...|Action|Crime|Dram...|    5.0|2016-04-23 04:02:28|
|    318|Shawshank Redempt...|         Crime|Drama|    4.5|2016-04-23 04:01:38|
|    356| Forrest Gump (1994)|Comedy|Drama|Roma...|    4.0|2016-04-23 04:07:59|
|    364|Lion King, The (1...|Adventure|Animati...|    5.0|2016-04-23 04:02:51|
|    527|Schindler's List ...|           Drama|War|    5.0|2016-04-23 04:00:22|
|    588|      Aladdin (1992)|Adventure|Animati...|    5.0|2016-04-23 04:05:28|
|    595|Beauty and the Be...|Animation|Childre...|    4.0|2016-04-23 04:06:12|
|    858|Godfather, The (1...|         Crime|Drama|    5.0|2016-04-23 04:00:51|
|    912|   Casablanca (1942)|       Drama|Romance|    4.5|2016-04-23 04:08:09|
+-------+--------------------+--------------------+-------+-------------------+
only showing top 10 rows

ユーザー1さんと同様に、アクション、ドラマ、コメディ、アドベンチャーなどを好んでいるようです。なんとなくではありますが、ユーザー319さんが好む映画をユーザー1さんにオススメすれば、喜んでもらえる可能性は高そうです。

なお、この記事では触れませんが、Amazon Personalizeでは機械学習で標準的な結果の評価指標を計算してくれるAPIもあります。この機能を使うと、「なんとなく」ではなくきちんと精度を計算することができます。
ソリューションバージョンを評価する
また、評価指標については、過去の記事を御覧下さい。
推薦システムの基本的な評価指標について整理してみた

この記事では、分かりやすさのために「この映画を見た人は、この映画も見ています」という協調フィルタと呼ばれる機能の側面を説明しましたが、実際のAmazon Personalizeのアルゴリズムでは時間情報が重視されていて、古い情報よりも新しい情報を重視しユーザーが次に選びそうな情報を推薦する仕組みになっています。その辺りの説明はこのAmazonによるスライドで分かりやすく説明されていますので、ぜひご覧下さい。

利用料金の注意

Amazon Personalizeは、大きく3つの点で課金されます。

  • 登録データ容量
  • データの学習
  • 情報推薦

このうち、データの学習と情報推薦に関してはWeb-APIにアクセスしなければ料金は発生しませんが、登録したデータに関しては削除しない限り料金が発生するので注意して下さい。特に、今回の記事では使用しなかったAmazon S3に一時的にデータを置きAmazon Personalizeにデータを転送する方法なら、Amazon S3を見ることでデータの量が確認できますが、Amazon Personalize Web-APIで情報推薦サービスを実現する(3)で説明したイベントトラッカーを使ってデータを送信する方法だと、どれくらいのデータを送信したか確認できません。不要な場合、キャンペーン、ソリューション、データセットなど全て削除することをお薦め致します。

おわりに

今回の一連の記事では、Amazon PersonalizeのWeb-APIを用いて、データを登録して機械学習をし、映画情報の推薦結果を得るまでの操作方法を説明しました。Web-APIを使っているので、Twitter APIFacebook APIのように、Webアプリケーションに簡単に組み込むことができます。今回説明した他にも、メタデータを使ってより高度な学習をする方法やパーソナライズランキングを取得する方法など沢山の機能がありますので、またの機会をお待ち頂けますと幸いです。

ts

大学で民俗学や宗教についてのフィールドワークを楽しんでいたのですが,うっかり新設された結び目理論と幾何学を勉強する研究室に移ってしまい,さらに大学院では一般相対性理論を研究するという迷走した人生を歩んでいます.プログラミングが苦手で勉強中です.

Recommends

こちらもおすすめ

Special Topics

注目記事はこちら