LoginSignup
26
28

More than 5 years have passed since last update.

Amazon Personalizeでレコメンドしてみる話

Last updated at Posted at 2019-06-22
1 / 32

Amazon Personalizeとは

先日東京リージョンでGAになったばかりのサービスです。
amazon開くと、あなたにオススメとかいいつつ、欲しかったあの商品やら気になるあの商品やらがずらりと表示されたりするけど、要はああいうシステムをamazonが使わせてくれると言う話。
普通、レコメンドといえば、TensorFlowやらもしくはSageMakerやら使ってゴリゴリやらなくちゃいけないけど、そういうのが完全マネージドで提供され、よくわかんなくてもポチポチしてればできちゃいます。


使ってみた背景

弊社、とある通販サイトを運営してます。そしてやはりレコメンド商品表示枠というのはあって、ここには外部のASPサービスを使っています。ただ、コレ、顧客の購買情報とかみてないんですわ。
ここ、機械学習の出番じゃね?って常々思っていたところ、ちょうどPersonalizeが使えるようになったので、導入に向けて試しておくのです。

ちなみに筆者、機械学習は毛が生えたド素人に毛が生えた程度のド素人です。


シナリオ

  • ユーザーは30人いてうちの5人は購入履歴なし
  • 好みに応じて購買する商品が違う
  • 商品(お菓子)は10種類
  • 若年層はチョコが好き
  • 高齢層は和菓子が好き
  • 購買履歴は10000件ある

ユーザー一覧

ID 好み 年齢 性別
1 チョコが好き 20
2 スナックが好き 40
3 甘いものが好き 15
4 和菓子が好き 60
5 チョコは食べない 30
6 チョコが好き 20
7 スナックが好き 10
8 甘いものが好き 18
9 和菓子が好き 50
10 チョコは食べない 50
11 チョコが好き 30
12 スナックが好き 20
13 甘いものが好き 25
14 和菓子が好き 30
15 チョコは食べない 70
16 チョコが好き 8
17 スナックが好き 30
18 甘いものが好き 35
19 和菓子が好き 35
20 チョコは食べない 20
21 チョコが好き 20
22 スナックが好き 40
23 甘いものが好き 15
24 和菓子が好き 60
25 チョコは食べない 80
26 購買履歴なし 10
27 購買履歴なし 40
28 購買履歴なし 15
29 購買履歴なし 70
30 購買履歴なし 65

商品一覧

商品名 ID GENRE
板チョコ 1 chocolate,sweet
チョコフレーク 2 chocolate,sweet
チョコクッキー 3 chocolate,sweet,cookie
ポテチ 4 snack,salty
クッキー 5 cookie
羊羹 6 japanese sweets,sweet
えびせん 7 snack,salty
チリポテト 8 snack,hot
バニラアイス 9 ice,sweet
せんべい 10 japanese sweets,salty

購買データ

gendatas.py
import random
for i in range(10000):
     user_id = random.randrange(1, 26)
     item_id = 1
     if user_id  % 5 == 1:
       item_id = random.choice([1,2,3])
     elif user_id % 5 == 2:
       item_id = random.choice([4,8,7])
     elif user_id % 5 == 3:
       item_id = random.choice([1,6,9])
     elif user_id % 5 == 4:
       item_id = random.choice([6,7,10])
     elif user_id % 5 == 0:
       item_id = random.choice([4,5,9])
     else:
       item_id = random.randrange(1, 10)
     timestamp = random.randrange(886324817, 1086324817)
     print(str(user_id) + ',' + str(item_id) + ',' + str(timestamp))

$ echo 'USER_ID,ITEM_ID,TIMESTAMP' > data.csv
$ python gendatas.py >> data.csv
$ head -n 5 data.csv 
USER_ID,ITEM_ID,TIMESTAMP
3,9,1035139806
11,3,1033513918
10,9,1065571205
21,1,1010453337
$ head -n 5 users.csv 
USER_ID,AGE,GENDER
1,20,男
2,40,男
3,15,女
4,60,女
$ head -n 5 items.csv                                                                              
ITEM_ID,GENRE
1,chocolate|sweet
2,chocolate|sweet
3,chocolate|sweet|cookie
4,snack,salty

S3に保存

$ aws s3 mb s3://amazon-personalize-shopping-example
$ mkdir data item user
$ mv data.csv data/
$ mv items.csv item/
$ mv users.csv user/
$ aws s3 sync data s3://amazon-personalize-shopping-example/data
upload: data/data.csv to s3://amazon-personalize-shopping-example/data/data.csv
$ aws s3 sync user s3://amazon-personalize-shopping-example/user
upload: user/users.csv to s3://amazon-personalize-shopping-example/user/users.csv
$ aws s3 sync item s3://amazon-personalize-shopping-example/item
upload: item/items.csv to s3://amazon-personalize-shopping-example/item/items.csv

バケットポリシー

{
     "Version": "2012-10-17",
     "Id": "PersonalizeS3BucketAccessPolicy",
     "Statement": [
         {
             "Sid": "PersonalizeS3BucketAccessPolicy",
             "Effect": "Allow",
             "Principal": {
                 "Service": "personalize.amazonaws.com"
             },
             "Action": [
                 "s3:GetObject",
                 "s3:ListBucket"
             ],
             "Resource": [
                 "arn:aws:s3:::amazon-personalize-shopping-example",
                 "arn:aws:s3:::amazon-personalize-shopping-example/*"
             ]
         }
     ]
}

大筋

  • Personalize Consoleを開く
  • Get started
  • DataSetグループの作成
  • ソリューションの作成 (つまりトレーニング)
  • キャンペーンを作成する (エンドポイントができる)
  • レコメンデーションを取得する

DataSetグループの作成

subject value
Dataset group name shopping-example-ds-grp
Dataset name shopping-example-ds
Schema name shopping-example-schema

DataSet Schema

{
  "type": "record",
  "name": "Interactions",
  "namespace": "com.amazonaws.personalize.schema",
  "fields": [
      {
          "name": "USER_ID",
          "type": "string"
      },
      {
          "name": "ITEM_ID",
          "type": "string"
      },
      {
          "name": "TIMESTAMP",
          "type": "long"
      }
  ],
  "version": "1.0"
}

Dataset import job details

Roleは新規に作る。
スクリーンショット 2019-06-21 21.21.10.png


User Schema

Dataset name = shopping-example-user

shopping-example-user-schema
{
  "type": "record",
  "name": "Users",
  "namespace": "com.amazonaws.personalize.schema",
  "fields": [
      {
          "name": "USER_ID",
          "type": "string"
      },
      {
          "name": "AGE",
          "type": "int"
      },
      {
          "name": "GENDER",
          "type": "string",
          "categorical": true
      }
  ],
  "version": "1.0"
}

Userdata import job details

スクリーンショット 2019-06-21 21.30.14.png


Item Schema

Dataset name = shopping-example-item

shopping-example-item-schema
{
  "type": "record",
  "name": "Items",
  "namespace": "com.amazonaws.personalize.schema",
  "fields": [
      {
          "name": "ITEM_ID",
          "type": "string"
      },
      {
          "name": "GENRE",
          "type": "string",
          "categorical": true
      }
  ],
  "version": "1.0"
}

Itemdata import job details

スクリーンショット 2019-06-21 21.32.18.png


待つ

スクリーンショット 2019-06-21 21.34.35.png


ソリューションの作成

subject value
Solution name shopping-example-solution
Receipe selection automatic

automaticにするとaws-hrnnとaws-hrnn-metadataが選択されていました。
階層型リカレントニューラルネットワーク (HRNN) ってやつらしい。

https://docs.aws.amazon.com/ja_jp/personalize/latest/dg/native-recipe-hrnn.html
https://docs.aws.amazon.com/ja_jp/personalize/latest/dg/native-recipe-hrnn-metadata.html


キャンペーンを開始する

subject value
Campaign name shopping-example-cp
Minimum provisioned TPS 1

CLIでテスト

getitems.py
#ec2実行ロールにpersonalize:GetRecommendationsの権限が必要

import boto3
import sys

params = sys.argv
length = len(params)
itemlist = ['N','板チョコ','チョコフレーク','チョコクッキー','ポテチ','クッキー','羊羹','えびせん','チリポテト','バニラアイス','せんべい']

personalizert = boto3.client('personalize-runtime', 
region_name='ap-northeast-1')

response=personalizert.get_recommendations(

campaignArn="arn:aws:personalize:ap-northeast-1:xxxxxxxx:campaign/shopping-example-cp",
     userId=params[1])

print("Recommended items")

for item in response['itemList'][0:5]:
         print (itemlist[int(item['itemId'])])

実行テスト

購買履歴ありユーザ

$ python getitems.py 1 #チョコが好き
Recommended items
板チョコ
チョコフレーク
チョコクッキー
バニラアイス
羊羹
$ python getitems.py 2 #スナックが好き
Recommended items
ポテチ
チリポテト
えびせん
クッキー
バニラアイス
$ python getitems.py 4 #和菓子が好き
Recommended items
せんべい
羊羹
えびせん
ポテチ
チリポテ
$ python getitems.py 6 #チョコが好き
Recommended items
板チョコ
チョコフレーク
チョコクッキー
バニラアイス
羊羹

購買履歴なしユーザ

$ python getitems.py 26
Recommended items
羊羹
チョコフレーク
えびせん
クッキー
チリポテト
$ python getitems.py 27
Recommended items
羊羹
チョコフレーク
えびせん
クッキー
チリポテト
$ python getitems.py 28
Recommended items
羊羹
チョコフレーク
えびせん
クッキー
チリポテト


結果

購買履歴ありユーザは好みに応じたレコメンドが表示されていた風ではあるものの、購買履歴なしユーザは期待した動作をしていなかった。
年齢や性別が近いものをうまく考慮してほしかったが、単純に購入されている総数順っぽい。
DataSetやSchemaの設計で解決しないか今後、検証する予定。


延長戦

商品2つとそれに対する購買履歴を2x2追加してみました。item11がチョコアイス、12が柿の種という設定です

$ tac data/data.csv | head -n 4
27,12,986218443
27,12,1042178066
26,11,986218442
26,11,1042178065
$ tac item/items.csv | head -n 2
12,japanese sweets|salty
11,chocolate|sweet

実行

$ python getitems.py 26 #10歳女
Recommended items
板チョコ
バニラアイス
羊羹
チョコクッキー
ポテチ
$ python getitems.py 27 #40歳男
Recommended items
ポテチ
えびせん
バニラアイス
チリポテト
羊羹

延長戦の結果

  • チョコアイス、柿の種は上位に上がってこないものの、好みの傾向は反映されているようにみえる
  • 新商品など、購入数は少ないけどレコメンドに載せたいものを載せるのが難しい

総じて言うと・・
なんだか微妙


参考にさせていただいたサイト


ちなみに

6月23日【ブロックチェーンエンジニアが教える】機械学習・ML Ops・kaggle勉強会 にてLTをさせていただこうと思い、記事にしました。


最後に全件をずらっと

$ for i in 1 2 3 4 5 26 27 28; do echo "${i}:"; python getitems.py $i; done
1:
Recommended items
板チョコ
チョコフレーク
チョコクッキー
バニラアイス
羊羹
ポテチ
クッキー
チョコアイス
柿の種
チリポテト
えびせん
せんべい
2:
Recommended items
ポテチ
チリポテト
えびせん
クッキー
バニラアイス
チョコフレーク
柿の種
チョコクッキー
チョコアイス
羊羹
せんべい
板チョコ
3:
Recommended items
バニラアイス
羊羹
板チョコ
クッキー
ポテチ
チョコクッキー
チョコフレーク
えびせん
せんべい
柿の種
チョコアイス
チリポテト
4:
Recommended items
せんべい
羊羹
えびせん
ポテチ
チリポテト
バニラアイス
板チョコ
クッキー
チョコアイス
柿の種
チョコクッキー
チョコフレーク
5:
Recommended items
バニラアイス
クッキー
ポテチ
羊羹
板チョコ
えびせん
チリポテト
せんべい
チョコアイス
柿の種
チョコクッキー
チョコフレーク
26:
Recommended items
板チョコ
バニラアイス
羊羹
チョコクッキー
ポテチ
チョコフレーク
えびせん
チリポテト
クッキー
せんべい
チョコアイス
柿の種
27:
Recommended items
ポテチ
えびせん
バニラアイス
チリポテト
羊羹
板チョコ
クッキー
チョコクッキー
チョコフレーク
せんべい
柿の種
チョコアイス
28:
Recommended items
ポテチ
バニラアイス
えびせん
羊羹
板チョコ
チリポテト
クッキー
チョコクッキー
チョコフレーク
せんべい
チョコアイス
柿の種

スナック好きユーザ

$ python getitems.py 2 #40|男
Recommended items
ポテチ
チリポテト
えびせん
クッキー
バニラアイス
チョコフレーク
柿の種
チョコクッキー
チョコアイス
羊羹
せんべい
板チョコ
$ python getitems.py 7 #10|男
Recommended items
チリポテト
ポテチ
えびせん
せんべい
羊羹
クッキー
チョコクッキー
チョコフレーク
バニラアイス
柿の種
チョコアイス
板チョコ
$ python getitems.py 12 #20|女
Recommended items
チリポテト
ポテチ
えびせん
クッキー
せんべい
バニラアイス
羊羹
チョコクッキー
チョコフレーク
チョコアイス
柿の種
板チョコ
$ python getitems.py 17 #30|男
Recommended items
ポテチ
チリポテト
えびせん
せんべい
クッキー
羊羹
チョコクッキー
チョコフレーク
バニラアイス
チョコアイス
柿の種
板チョコ
$ python getitems.py 22 #40|女
Recommended items
チリポテト
ポテチ
えびせん
せんべい
羊羹
チョコクッキー
チョコフレーク
クッキー
チョコアイス
バニラアイス
柿の種
板チョコ
26
28
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
28