Amazon Personalizeにプロモーション機能が追加:レコメンド結果の一部を特定条件のアイテムにコントロールできるようになりました

2022.08.31

こんちには。

データアナリティクス事業本部機械学習チームの中村です。

今回はAmazon Personalizeの新機能である特定アイテムのプロモーション機能についてご紹介します。

AWS公式ブログでは以下の記事で紹介されています。

プロモーション機能とは

特定の条件に当てはまるアイテムを、ある指定割合でレコメンドに混ぜることが可能となる機能です。

例えば、ECサイトなどで商品を販売する場合、レコメンドとは独立して以下のようなシーンがあるかと思います。

  • ハロウィンの時期にはそのアイテムをより推薦してユーザに購入させたい

そういった場合に、プロモーション機能が活用できます。

この機能により、ハロウィン関係のアイテムを20%までレコメンドに混ぜる、などが可能となります。

もともとAmazon Personalizeには、レコメンド全体を特定の条件に絞るフィルターの機能がありました。

このフィルターを指定割合で部分的に適用できるようになったと考えれば良いと思います。

(実際にプロモーション機能を作成する場合も、一旦フィルターを作成してそれを使用して構築する形となります。)

特徴まとめ

以降、様々なパターンで検証しますが、冒頭にその特徴や留意点をまとめておきます。

  • プロモーション機能はDomain特化、Customの双方で使用可能
  • プロモーション機能はCustomは一部のレシピのみで使用可能
  • プロモーションしたいアイテムが元々一定割合以上あった場合は、元々の件数分残る
  • 存在しない条件でプロモーションした場合は、プロモーション無しと同じ動作となる
  • プロモーションに設定するフィルターは一つのみ
  • プロモーション機能はフィルターと同時に使用可能
    • 同時に使用する場合、プロモーション側はフィルターの条件を満たさなくて良い
  • フィルター側に存在しない条件を設定した場合、プロモーション機能の件数分だけ取得される
    • そのため、レコメンド数が要求したもの以下の個数となる
  • Customでプロモーション機能を使用する場合、アイテム毎のスコアが変化するため留意が必要
    • Domain特化の場合はアイテム毎のスコアが取得できないためCustomの場合のみ

対象となるレシピ

AWS公式ブログによれば、プロモーション機能を使用できるレシピはDomainごとに異なります。

Domainを「Custom」とする場合は以下のレシピで使用可能です。

  • User-Personalizationレシピ
  • Similar-Itemsレシピ

Domainを特化型の「E-commerce」または「Video on demand」とする場合はすべてのレシピで使用可能です。

今回は、Domainを「E-commerce」で作成し、レシピは「Recommended for you」を使用してレコメンダーを構築します。

その後プロモーション機能を試していきます。

レコメンダー構築

dataset group作成

まずはdataset groupを作成します。

名前を入力して、Domainは「E-commerce」を選択します。

dataset作成(interactions)

dataset groupの作成が終わると、interactionsのdataset作成画面に遷移します。

datasetの名前とスキーマ名を入力します。

スキーマは以下のようにします(デフォルトと同じです)。

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

上記を入力し、ページ下部のボタンを押下します。

import job作成(interactions)

dataset作成が終わるとimport job作成画面に遷移します。

「Import data from S3」を選択して、import job nameを入力します。

次にS3にデータを準備します。公式ブログに沿って以下からinteractions.csvをダウンロードします。

csvファイルを任意のS3バケットにアップロードします。

S3バケットを作成します。設定はデフォルトのままで実施します。

バケットポリシーは以下を設定しておきます。

{
    "Version": "2012-10-17",
    "Id": "PersonalizeS3BucketAccessPolicy",
    "Statement": [
        {
            "Sid": "PersonalizeS3BucketAccessPolicy",
            "Effect": "Allow",
            "Principal": {
                "Service": "personalize.amazonaws.com"
            },
            "Action": [
                "s3:GetObject",
                "s3:ListBucket",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::nakamura-sample-2022-08-26-personalize",
                "arn:aws:s3:::nakamura-sample-2022-08-26-personalize/*"
            ]
        }
    ]
}

import jobにS3のURIを入力します。

importに必要なIAMロールを作成します。

ページ下部のボタンを押下する。

ロードが始まります。

Interaction data activeとなったらロードが完了です。

dataset作成(items)

interactionsと同様に、itemsデータセットもアップロードしていきます。

公式ブログに沿って以下からitems.csvをダウンロードします。

このcsvファイルをS3バケットにアップロードします。

以下のImport item dataを押下します。

以下のようにdatasetの名前とスキーマ名を入力します。

スキーマはデフォルトではなく以下を使用します。

{
    "type": "record",
    "name": "Items",
    "namespace": "com.amazonaws.personalize.schema",
    "fields": [
        {
            "name": "ITEM_ID",
            "type": "string"
        },
        {
            "name": "PRICE",
            "type": "float"
        },
        {
            "name": "CATEGORY_L1",
            "type": ["string"],
            "categorical": true
        },
        {
            "name": "CATEGORY_L2",
            "type": ["string"],
            "categorical": true
        },
        {
            "name": "GENDER",
            "type": ["string"],
            "categorical": true
        }
    ],
    "version": "1.0"
}

上記を入力後、ページ下部のボタンを押下します。

import job作成(items)

あとはinteractions側と同様にimport jobを作成します。

作成すると以下のようにロードが始まります。

しばらく待つとロードが完了し以下の画面となります。

recommender作成

ページ下部に進み、Create recommendersから作成を進めます。

レシピとしては、"Recommended for you"のみにチェックし、ページ下部のボタンを押下します。

レコメンダーの作成が始まります。モデルの学習などを含むため時間は数十分かかります。

(今回のデータセットでは約50分程度で作成完了しました)

作成が完了すると、以下のようにアクティブになります。

filter作成

次にプロモーションをするためにフィルターを作成します。

Overwiewメニューから「Create filter」を押下します。

作成するフィルタは、公式ブログと同一にしてみます。

動的フィルタとして変数$CATEGORYを条件に使用します。

$CATEGORYをitemsのCATEGORY_L2と比較して一致するものを取得するフィルターとします。

ページ下部のボタンを押下します。

こちらのフィルターを使用して実際にプロモーション機能を使用してみます。

プロモーション機能の検証

ここからはboto3を使って実施していきます。

(マネジメントコンソールで実施されたい場合は、Recommender一覧からRecommenderを選択して、Test recommenderボタンから実施されてください。

準備

冒頭で以下を実行します。

import boto3
from boto3.session import Session
import json
import pathlib
import pandas as pd

items = pd.read_csv("items.csv")

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

リソースのARNは作成したものを指定してください。

recommenderArn = "<your recommender arn>"
filterArn = "<your filter arn>"

プロモーション無し

まずはプロモーション機能なしでやってみます。テスト用のユーザIDを1000として以下を実行します。

response_get_recommendations = client_personalize_runtime.get_recommendations(
    userId = "1000",
    numResults = 25,
    recommenderArn = recommenderArn
)
recommends = pd.DataFrame(response_get_recommendations["itemList"])
recommends.merge(items, how='inner', left_on='itemId', right_on='ITEM_ID'\
    )[['itemId', 'CATEGORY_L2']]

結果は以下のようになります。(確認のためitems.csvとjoinして示しています)

itemId CATEGORY_L2
bd446035-3a6f-49b0-a1c3-d346d12cb877 valentine
1ef8b06f-0a08-484a-a851-8b87363f7f49 chairs
269f2084-4e82-4ed8-a8d9-624ef27cf681 halloween
b57916d2-bc8f-440a-970e-b7413a9122aa christmas
ebaa480b-e069-4ff5-bb2c-ec8b33898626 valentine
716808c3-e65e-4fe2-8aae-6d8370ff8693 halloween
59924a8d-3168-4a39-80f2-0d94283fd6d5 tables
09b832ce-73fc-49f4-bd8b-5d5e4fe9fe72 valentine
5730d368-9c6d-48b4-ad27-c180e486621c tables
6b985b88-1471-4b1d-a4db-2f26810c9da2 sofas
cf4ea7c0-c24a-42d1-a72f-d2b8598e1274 christmas
fe00d7b6-7c1a-482d-8552-cb9654f98286 sofas
86a3fc89-b3d4-4bbc-b168-696de7871ac9 tables
29359485-1173-4a37-9bb7-6065c58a4f9e chairs
47636cd1-731c-47d1-8d0b-612575af0a5c chairs
1dd4c2da-d174-43b1-8d40-fadc666c26c9 tables
c26e6166-6609-4e61-a674-3e58b6dfc7fc tables
02b959b5-7fa8-44ad-8eb2-faf6b750980e sofas
cfe2daa9-3b76-45c9-9d36-2d11472f4005 sofas
335cb058-b670-42d0-89a8-305fe91291cf tables
de374b6b-7636-4784-b555-b5b37ee158e0 tables
546bdb90-945a-48e8-84c7-557f8c48a032 sofas
d843fe25-e7d1-40fb-84b0-64bdedf9bed6 christmas
43dbbd80-b7f7-44c0-a942-e144006cc020 sofas
91d060b5-149e-4ece-bbe2-ddcd08e1f24e halloween

プロモーション機能あり

次にプロモーション機能ありを試してみます。引数にpromotionsを以下のように追加して実行します。

response_get_recommendations = client_personalize_runtime.get_recommendations(
    userId = "1000",
    numResults = 25,
    recommenderArn = recommenderArn,
    promotions = [{
        "name": "promotion_halloween",
        "percentPromotedItems": 20,
        "filterArn": filterArn,
        "filterValues": {
            "CATEGORY": "\"halloween\""
        }
    }]
)
recommends = pd.DataFrame(response_get_recommendations["itemList"])
recommends.merge(items, how='inner', left_on='itemId', right_on='ITEM_ID'\
    )[['itemId', 'promotionName', 'CATEGORY_L2']]

以下がその結果となります。

itemId promotionName CATEGORY_L2
bd446035-3a6f-49b0-a1c3-d346d12cb877 NaN valentine
1ef8b06f-0a08-484a-a851-8b87363f7f49 NaN chairs
b57916d2-bc8f-440a-970e-b7413a9122aa NaN christmas
ebaa480b-e069-4ff5-bb2c-ec8b33898626 NaN valentine
269f2084-4e82-4ed8-a8d9-624ef27cf681 promotion_halloween halloween
59924a8d-3168-4a39-80f2-0d94283fd6d5 NaN tables
716808c3-e65e-4fe2-8aae-6d8370ff8693 promotion_halloween halloween
09b832ce-73fc-49f4-bd8b-5d5e4fe9fe72 NaN valentine
5730d368-9c6d-48b4-ad27-c180e486621c NaN tables
6b985b88-1471-4b1d-a4db-2f26810c9da2 NaN sofas
cf4ea7c0-c24a-42d1-a72f-d2b8598e1274 NaN christmas
fe00d7b6-7c1a-482d-8552-cb9654f98286 NaN sofas
86a3fc89-b3d4-4bbc-b168-696de7871ac9 NaN tables
29359485-1173-4a37-9bb7-6065c58a4f9e NaN chairs
91d060b5-149e-4ece-bbe2-ddcd08e1f24e promotion_halloween halloween
47636cd1-731c-47d1-8d0b-612575af0a5c NaN chairs
1dd4c2da-d174-43b1-8d40-fadc666c26c9 NaN tables
c26e6166-6609-4e61-a674-3e58b6dfc7fc NaN tables
02b959b5-7fa8-44ad-8eb2-faf6b750980e NaN sofas
c48cdd85-79da-4903-8bbf-93ee217f1fb6 promotion_halloween halloween
6d7b19ca-b79f-4246-9c6e-f043121783c0 promotion_halloween halloween
cfe2daa9-3b76-45c9-9d36-2d11472f4005 NaN sofas
335cb058-b670-42d0-89a8-305fe91291cf NaN tables
de374b6b-7636-4784-b555-b5b37ee158e0 NaN tables
546bdb90-945a-48e8-84c7-557f8c48a032 NaN sofas

プロモーション無しではhalloweenは3件でしたが、

プロモーション機能により25件のうち20%の5件がhalloweenのアイテムとなっていることが分かります。

また、プロモーションを有効とした場合、プロモーションの対象となったアイテムに

promotionNameが付与されるため、どのアイテムがプロモーションされたかわかる形となります。

プロモーションしたいアイテムが元々一定以上あった場合

プロモーションしたいアイテムが指定した割合より元々高かった場合はどのような挙動になるのでしょうか?

このユーザIDでは元々tablesというカテゴリが多いようですので、

以下のようにpromotionの条件をtablesに修正して試してみます。

response_get_recommendations = client_personalize_runtime.get_recommendations(
    userId = "1000",
    numResults = 25,
    recommenderArn = recommenderArn,
    promotions = [{
        "name": "promotion_tables",
        "percentPromotedItems": 20,
        "filterArn": filterArn,
        "filterValues": {
            "CATEGORY": "\"tables\""
        }
    }]
)
recommends = pd.DataFrame(response_get_recommendations["itemList"])
recommends.merge(items, how='inner', left_on='itemId', right_on='ITEM_ID')\
    [['itemId', 'promotionName', 'CATEGORY_L2']]

結果は以下のようになりました。

itemId promotionName CATEGORY_L2
bd446035-3a6f-49b0-a1c3-d346d12cb877 NaN valentine
1ef8b06f-0a08-484a-a851-8b87363f7f49 NaN chairs
269f2084-4e82-4ed8-a8d9-624ef27cf681 NaN halloween
b57916d2-bc8f-440a-970e-b7413a9122aa NaN christmas
59924a8d-3168-4a39-80f2-0d94283fd6d5 promotion_tables tables
ebaa480b-e069-4ff5-bb2c-ec8b33898626 NaN valentine
5730d368-9c6d-48b4-ad27-c180e486621c promotion_tables tables
716808c3-e65e-4fe2-8aae-6d8370ff8693 NaN halloween
09b832ce-73fc-49f4-bd8b-5d5e4fe9fe72 NaN valentine
6b985b88-1471-4b1d-a4db-2f26810c9da2 NaN sofas
cf4ea7c0-c24a-42d1-a72f-d2b8598e1274 NaN christmas
fe00d7b6-7c1a-482d-8552-cb9654f98286 NaN sofas
29359485-1173-4a37-9bb7-6065c58a4f9e NaN chairs
47636cd1-731c-47d1-8d0b-612575af0a5c NaN chairs
86a3fc89-b3d4-4bbc-b168-696de7871ac9 promotion_tables tables
02b959b5-7fa8-44ad-8eb2-faf6b750980e NaN sofas
cfe2daa9-3b76-45c9-9d36-2d11472f4005 NaN sofas
335cb058-b670-42d0-89a8-305fe91291cf NaN tables
de374b6b-7636-4784-b555-b5b37ee158e0 NaN tables
1dd4c2da-d174-43b1-8d40-fadc666c26c9 promotion_tables tables
c26e6166-6609-4e61-a674-3e58b6dfc7fc promotion_tables tables
546bdb90-945a-48e8-84c7-557f8c48a032 NaN sofas
d843fe25-e7d1-40fb-84b0-64bdedf9bed6 NaN christmas
43dbbd80-b7f7-44c0-a942-e144006cc020 NaN sofas
91d060b5-149e-4ece-bbe2-ddcd08e1f24e NaN halloween

promotionNameが付与されているのは5件のみですが、

tablesのアイテム数はプロモーション無しの時と同様に7件あります。

ですので、すべてのユーザに対して指定した割合の20%になってしまうわけではなく、

元々プロモーションしたいものが多いユーザのレコメンデーションについては

その多い状態が維持されると考えて良さそうです。

存在しない条件をプロモーションに設定した場合

あり得ない条件を設定するとどのようになるでしょうか?

以下のようにpromotionの条件に適当な文字列hogehogeと修正して試してみます。

response_get_recommendations = client_personalize_runtime.get_recommendations(
    userId = "1000",
    numResults = 25,
    recommenderArn = recommenderArn,
    promotions = [{
        "name": "promotion_hogehoge",
        "percentPromotedItems": 20,
        "filterArn": filterArn,
        "filterValues": {
            "CATEGORY": "\"hogehoge\""
        }
    }]
)
recommends = pd.DataFrame(response_get_recommendations["itemList"])
recommends.merge(items, how='inner', left_on='itemId', right_on='ITEM_ID'\
    )[['itemId', 'CATEGORY_L2']]

結果は以下のようになりました。

itemId CATEGORY_L2
bd446035-3a6f-49b0-a1c3-d346d12cb877 valentine
1ef8b06f-0a08-484a-a851-8b87363f7f49 chairs
269f2084-4e82-4ed8-a8d9-624ef27cf681 halloween
b57916d2-bc8f-440a-970e-b7413a9122aa christmas
ebaa480b-e069-4ff5-bb2c-ec8b33898626 valentine
716808c3-e65e-4fe2-8aae-6d8370ff8693 halloween
59924a8d-3168-4a39-80f2-0d94283fd6d5 tables
09b832ce-73fc-49f4-bd8b-5d5e4fe9fe72 valentine
5730d368-9c6d-48b4-ad27-c180e486621c tables
6b985b88-1471-4b1d-a4db-2f26810c9da2 sofas
cf4ea7c0-c24a-42d1-a72f-d2b8598e1274 christmas
fe00d7b6-7c1a-482d-8552-cb9654f98286 sofas
86a3fc89-b3d4-4bbc-b168-696de7871ac9 tables
29359485-1173-4a37-9bb7-6065c58a4f9e chairs
47636cd1-731c-47d1-8d0b-612575af0a5c chairs
1dd4c2da-d174-43b1-8d40-fadc666c26c9 tables
c26e6166-6609-4e61-a674-3e58b6dfc7fc tables
02b959b5-7fa8-44ad-8eb2-faf6b750980e sofas
cfe2daa9-3b76-45c9-9d36-2d11472f4005 sofas
335cb058-b670-42d0-89a8-305fe91291cf tables
de374b6b-7636-4784-b555-b5b37ee158e0 tables
546bdb90-945a-48e8-84c7-557f8c48a032 sofas
d843fe25-e7d1-40fb-84b0-64bdedf9bed6 christmas
43dbbd80-b7f7-44c0-a942-e144006cc020 sofas
91d060b5-149e-4ece-bbe2-ddcd08e1f24e halloween

これはプロモーションを使用しない場合と同じ結果となっています。

プロモーションに設定するフィルターは一つのみ

プロモーションは引数がpromotionsとなっていますが、複数指定することはできないようです。

response_get_recommendations = client_personalize_runtime.get_recommendations(
    userId = "1000",
    numResults = 25,
    recommenderArn = recommenderArn,
    promotions = [{
        "name": "promotion_halloween",
        "percentPromotedItems": 20,
        "filterArn": filterArn,
        "filterValues": {
            "CATEGORY": "\"halloween\""
        },
    },{
        "name": "promotion_valentine",
        "percentPromotedItems": 20,
        "filterArn": filterArn,
        "filterValues": {
            "CATEGORY": "\"valentine\""
        },
    }]
)
recommends = pd.DataFrame(response_get_recommendations["itemList"])
recommends.merge(items, how='inner', left_on='itemId', right_on='ITEM_ID'\
    )[['itemId', 'promotionName', 'CATEGORY_L2']]

上記はエラーとなり、以下のように要素数1以下で指定するように要求されます。

ClientError: An error occurred (ValidationException) when calling the GetRecommendations operation: 1 validation error detected: Value '...' at 'promotions' failed to satisfy constraint: Member must have length less than or equal to 1

フィルターと同時にプロモーション機能を使う

こちらは公式ブログに例としてありますが、元々のレコメンデーションにフィルタを設定したうえで、

プロモーション機能も使用することができます。

以下のようにフィルターにはchristmasを、プロモーションにはhalloweenを設定してみました。

response_get_recommendations = client_personalize_runtime.get_recommendations(
    userId = "1000",
    numResults = 25,
    recommenderArn = recommenderArn,
    filterArn = filterArn,
    filterValues = {
        "CATEGORY": "\"christmas\""
    },
    promotions = [{
        "name": "promotion_tables",
        "percentPromotedItems": 20,
        "filterArn": filterArn,
        "filterValues": {
            "CATEGORY": "\"halloween\""
        }
    }]
)
recommends = pd.DataFrame(response_get_recommendations["itemList"])
recommends.merge(items, how='inner', left_on='itemId', right_on='ITEM_ID'\
    )[['itemId', 'promotionName', 'CATEGORY_L2']]

これにより、プロモーション以外はchristmasの商品、プロモーションはhalloweenの商品となりました。

itemId promotionName CATEGORY_L2
b57916d2-bc8f-440a-970e-b7413a9122aa NaN christmas
cf4ea7c0-c24a-42d1-a72f-d2b8598e1274 NaN christmas
d843fe25-e7d1-40fb-84b0-64bdedf9bed6 NaN christmas
0666855e-e1a2-446d-848e-864a92774721 NaN christmas
269f2084-4e82-4ed8-a8d9-624ef27cf681 promotion_halloween halloween
cd1a0228-7d3d-4782-a1fb-c1e99bc939b3 NaN christmas
716808c3-e65e-4fe2-8aae-6d8370ff8693 promotion_halloween halloween
11d3acc6-c567-45a2-a865-15723b41b162 NaN christmas
82110ac1-3eb0-4d4a-831e-9cf07e6816ef NaN christmas
11f55a4a-b03d-4d49-91ac-df8485164b4d NaN christmas
275c4b29-2dc5-48d9-8dc9-480314e40102 NaN christmas
bca5931d-fdd4-41f3-ac6f-8529e9f4e5b2 NaN christmas
a982d205-3cd1-4899-9591-1787b5422a80 NaN christmas
812b315c-fb4b-4103-8911-95968f9cc6c0 NaN christmas
91d060b5-149e-4ece-bbe2-ddcd08e1f24e promotion_halloween halloween
33308fd7-d70d-4b2a-a897-f3313609e86b NaN christmas
8c2eb441-f808-4c0b-8d7e-0f19869c00cb NaN christmas
f1e0660b-53db-4e9a-a86a-8a990d6b2988 NaN christmas
f6996563-3f1a-4254-a922-f5700cf66153 NaN christmas
c48cdd85-79da-4903-8bbf-93ee217f1fb6 promotion_halloween halloween
6d7b19ca-b79f-4246-9c6e-f043121783c0 promotion_halloween halloween
61b1ad14-4e70-4029-ba55-d17bbf4ab62b NaN christmas
6177b0fb-944b-41da-87ea-f0d643ed1953 NaN christmas
6d1ac1e7-39a2-49db-a9cb-6fa0d1393f88 NaN christmas
f48751db-ecd5-4e3c-9fef-82d45c4cf51a NaN christmas

フィルターに存在しない条件を設定してプロモーション機能を使った場合

以下のようにフィルター側の条件を、適当なhogehogeに設定して試してみます。

response_get_recommendations = client_personalize_runtime.get_recommendations(
    userId = "1000",
    numResults = 25,
    recommenderArn = recommenderArn,
    filterArn = filterArn,
    filterValues = {
        "CATEGORY": "\"hogehoge\""
    },
    promotions = [{
        "name": "promotion_halloween",
        "percentPromotedItems": 20,
        "filterArn": filterArn,
        "filterValues": {
            "CATEGORY": "\"halloween\""
        }
    }]
)
recommends = pd.DataFrame(response_get_recommendations["itemList"])
recommends.merge(items, how='inner', left_on='itemId', right_on='ITEM_ID'\
    )[['itemId', 'promotionName', 'CATEGORY_L2']]

結果は以下のようになります。

itemId promotionName CATEGORY_L2
269f2084-4e82-4ed8-a8d9-624ef27cf681 promotion_halloween halloween
716808c3-e65e-4fe2-8aae-6d8370ff8693 promotion_halloween halloween
91d060b5-149e-4ece-bbe2-ddcd08e1f24e promotion_halloween halloween
c48cdd85-79da-4903-8bbf-93ee217f1fb6 promotion_halloween halloween
6d7b19ca-b79f-4246-9c6e-f043121783c0 promotion_halloween halloween

プロモーションされたアイテムのみ残るような形となり、

元々のフィルターとは無関係にプロモーションされることが分かります。

この場合、レコメンド件数として要求したnumResults = 25より少ないアイテム数となるため、注意が必要です。

Domainを「Custom」とする場合

プロモーションによりスコアが変化する

Domainを「Custom」とする場合、以下のレシピがプロモーションに対応します。

  • User-Personalizationレシピ
  • Similar-Itemsレシピ

Domainを「Custom」とした場合、レコメンド結果のスコアを得ることができるのですが、プロモーション機能はスコアに影響を与えるため注意が必要です。

User-Personalizationレシピを使用した場合の結果だけを以下に示します。

itemId promotionName CATEGORY_L2 score
be0967ed-5970-46b2-8d57-13065f647013 NaN tables 0.088827
bd446035-3a6f-49b0-a1c3-d346d12cb877 NaN valentine 0.048799
6bd33faa-9715-4f07-8858-bd509954b0b1 NaN christmas 0.026641
7c859d38-407a-4b5f-8125-c901bd3f5562 NaN tables 0.013924
7da40dc7-cacd-437c-90f0-6d72ae9c9472 NaN tables 0.012149
b2dbebe7-b9ba-409b-883a-d39ea9effef4 NaN christmas 0.011456
c48cdd85-79da-4903-8bbf-93ee217f1fb6 promotion_halloween halloween 0.304850
fe00d7b6-7c1a-482d-8552-cb9654f98286 NaN sofas 0.010693
ae8772cf-a7ad-4eb8-b12e-b286fd0a773f NaN valentine 0.010564
2c6ce233-7b8c-4866-b04e-ec71c083b797 NaN tables 0.010136
8cab347e-fa92-46c5-8a0e-371229e1c539 NaN dressers 0.009624
5395050a-b064-421f-9023-a269749bda4b NaN dressers 0.009580
2e4d07d7-8d48-4b16-a2b0-91cbaa1f7c89 NaN chairs 0.009121
079f8824-e91b-40ea-b159-5f7d0a9d9124 NaN christmas 0.009060
1d183b2d-09f0-409c-b1fe-8f91059654c9 promotion_halloween halloween 0.054629
4a43c5f7-090c-4cce-93fe-36062539ec38 NaN christmas 0.008973
9fcced83-5621-4c3c-88dd-f3110360c47e promotion_halloween halloween 0.052782
8c2eb441-f808-4c0b-8d7e-0f19869c00cb NaN christmas 0.008507
db3c71cc-6d04-4559-bafc-449a20029244 NaN tables 0.008331
812b315c-fb4b-4103-8911-95968f9cc6c0 NaN christmas 0.008155
ab6462b7-2061-42ba-a19f-a1efc877d800 NaN chairs 0.007716
a4fce4bd-5073-4434-ae7b-da6a4734708b NaN easter 0.007352
c28fe40f-00bd-4c82-897d-1aff37a615ed promotion_halloween halloween 0.046645
5c111431-fbc2-4a49-9c38-83dd5c37586a NaN easter 0.006429
e1372a53-ba17-48dc-8993-a57309805626 promotion_halloween halloween 0.044739

上記のように、プロモーションによりスコアは上昇するものの、

レコメンドの順番はスコア通りになっていないため注意が必要になります。

スコアを用いて何かしらのロジックを構築する際には気に留めておく必要がありそうです。

まとめ

いかがでしたでしょうか?

検証のため色々なパターンでプロモーション機能がどのように動作するか実施してみましたが、標準的な使い方の範囲であれば直感的で使いやすい印象を受けました。

これにより、よりレコメンドする側の意図に沿ったレコメンドをしやすくなったと考えられます。

こちらの記事がAmazon Personalizeを活用する際の参考になれば幸いです。