Amazon Personalizeのデータをチューニングしてみる

ワークショップに参加した時に気になっていたところがあったので、いろいろ触ってみました。 利用したデータ データはチュートリアルで用意されているものを使用します。 この入門ガイドでは、600 人のユーザーによる 9700 […]

広告ここから
広告ここまで

目次

    ワークショップに参加した時に気になっていたところがあったので、いろいろ触ってみました。

    利用したデータ

    データはチュートリアルで用意されているものを使用します。

    この入門ガイドでは、600 人のユーザーによる 9700 本の映画の 100,000 数の映画評価で構成される履歴データに基づいて、ユーザーに映画推薦を返すキャンペーンを作成する方法を説明します。

    https://docs.aws.amazon.com/personalize/latest/dg/getting-started.html

    チュートリアルの通りに作る

    まずはチュートリアルにしたがって推論エンドポイントを作ります。

    ここで使用するのはratings.csvで、映画のID(item_id)とユーザーのID(user_id)にタイムスタンプが加わったものを利用します。

    csvにratingという項目が増えていましたので、csvを開いてこれを削っておくと良いでしょう。

    作り方についてはチュートリアルをみてください。

    レコメンドを実行してみる

    Campaignが出来上がれば、実際にAPIコールして結果を見てみます。

    import {
      PersonalizeRuntime
    } from 'aws-sdk'
    
    const getRecomendations = async () => {
      const client = new PersonalizeRuntime({
        region: 'ap-northeast-1'
      })
      try {
        const params: PersonalizeRuntime.Types.GetRecommendationsRequest = {
          campaignArn: 'arn:aws:personalize:ap-northeast-1:99999999999:campaign/tutorial-campaign',
          userId: '1'
        }
        const result = await client.getRecommendations(params).promise()
        console.log(result.itemList)
      } catch (e) {
        console.log(e)
      }
    }
    
    getRecomendations()

    実行結果はこちらでした。

      [ { itemId: '1304' },
         { itemId: '1127' },
         { itemId: '1394' },
         { itemId: '2916' },
         { itemId: '3273' },
         { itemId: '1029' },
         { itemId: '2599' },
         { itemId: '1220' },
         { itemId: '1079' },
         { itemId: '1307' },
         { itemId: '2640' },
         { itemId: '1183' },
         { itemId: '1644' },
         { itemId: '1293' },
         { itemId: '2421' },
         { itemId: '2985' },
         { itemId: '2987' },
         { itemId: '2947' },
         { itemId: '1625' },
         { itemId: '2641' },
         { itemId: '1909' },
         { itemId: '1230' },
         { itemId: '2424' },
         { itemId: '2797' },
         { itemId: '2174' } ] }

    EVENT_TYPE / EVENT_VALUEを追加する

    続いてEVENT_TYPE / EVENT_VALUEをratings.csvに追加してみます。

    先ほど削除したratingを復活し、ヘッダーの項目名をEVENT_VALUEに変更します。そしてEVENT_TYPEという項目を追加し、Rainkingという値で全て埋めます。

    USER_ID,ITEM_ID,EVENT_TYPE,EVENT_VALUE,TIMESTAMP
    1,1,RATING,4,964982703
    1,3,RATING,4,964981247
    1,6,RATING,4,964982224
    1,47,RATING,5,964983815
    1,50,RATING,5,964982931
    ...

    続けてレコメンドを取得してみます。今回から違いがわかりやすいように、item_idでソートした結果を出します。

    const sortByItemId = (items: PersonalizeRuntime.PredictedItem[] | undefined): PersonalizeRuntime.PredictedItem[] | null => {
      if (!items) return null
      return items.sort((a, b) => {
        const aId = Number(a.itemId)
        const bId = Number(b.itemId)
        if (aId < bId) return -1;
        if (aId > bId) return 1;
        return 0;
      })
    }
    
    const getRecomendations = async () => {
      const client = new PersonalizeRuntime({
        region: 'ap-northeast-1'
      })
      try {
        const params: PersonalizeRuntime.Types.GetRecommendationsRequest = {
          campaignArn: 'arn:aws:personalize:ap-northeast-1:99999999:campaign/tutorial-campaign',
          userId: '1'
        }
        const result = await client.getRecommendations(params).promise()
        console.log(sortByItemId(result.itemList))
        const customResult = await client.getRecommendations({
          campaignArn: 'arn:aws:personalize:ap-northeast-1:999999999:campaign/customcampaign',
          userId: '1'
        }).promise()
        console.log(sortByItemId(customResult.itemList))
      } catch (e) {
        console.log(e)
      }
    }
    getRecomendations()

    キャンペーンのARNを差し替えた以外まったく同じ値を投げています。

    そしてこちらが実行結果。

    // チュートリアルの通り
    [ { itemId: '1029' },
      { itemId: '1079' },
      { itemId: '1127' },
      { itemId: '1183' },
      { itemId: '1220' },
      { itemId: '1230' },
      { itemId: '1293' },
      { itemId: '1304' },
      { itemId: '1307' },
      { itemId: '1394' },
      { itemId: '1625' },
      { itemId: '1644' },
      { itemId: '1909' },
      { itemId: '2174' },
      { itemId: '2421' },
      { itemId: '2424' },
      { itemId: '2599' },
      { itemId: '2640' },
      { itemId: '2641' },
      { itemId: '2797' },
      { itemId: '2916' },
      { itemId: '2947' },
      { itemId: '2985' },
      { itemId: '2987' },
      { itemId: '3273' } ]
    
    // EVENT_TYPE / EVENT_VALUEあり
    [ { itemId: '16' },
      { itemId: '223' },
      { itemId: '466' },
      { itemId: '520' },
      { itemId: '529' },
      { itemId: '594' },
      { itemId: '596' },
      { itemId: '708' },
      { itemId: '919' },
      { itemId: '1035' },
      { itemId: '1073' },
      { itemId: '1101' },
      { itemId: '1208' },
      { itemId: '1219' },
      { itemId: '1220' },
      { itemId: '1247' },
      { itemId: '1259' },
      { itemId: '1307' },
      { itemId: '1380' },
      { itemId: '1394' },
      { itemId: '1485' },
      { itemId: '2081' },
      { itemId: '2657' },
      { itemId: '2985' },
      { itemId: '3948' } ]

    2~3回実行しても同じ結果が返ってきます。なので推論モデルがかなり変わっている様子だなということが伺えます。

    Itemのcsvをアップロードする

    続いて映画の情報を追加してみます。Schemaは以下の設定にしました。

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

    またmovies.csvも1行目を書き換えています。

    $ head movies.csv 
    ITEM_ID,TITLE,GENRE
    1,Toy Story (1995),Adventure|Animation|Children|Comedy|Fantasy
    2,Jumanji (1995),Adventure|Children|Fantasy
    3,Grumpier Old Men (1995),Comedy|Romance
    4,Waiting to Exhale (1995),Comedy|Drama|Romance

    これも先ほどと同じようにBefore / Afterで2回getRecommendationsしてみます。

    // チュートリアル版
    [ { itemId: '1029' },
      { itemId: '1079' },
      { itemId: '1127' },
      { itemId: '1183' },
      { itemId: '1220' },
      { itemId: '1230' },
      { itemId: '1293' },
      { itemId: '1304' },
      { itemId: '1307' },
      { itemId: '1394' },
      { itemId: '1625' },
      { itemId: '1644' },
      { itemId: '1909' },
      { itemId: '2174' },
      { itemId: '2421' },
      { itemId: '2424' },
      { itemId: '2599' },
      { itemId: '2640' },
      { itemId: '2641' },
      { itemId: '2797' },
      { itemId: '2916' },
      { itemId: '2947' },
      { itemId: '2985' },
      { itemId: '2987' },
      { itemId: '3273' } ]
    
    // EVENT_TARGET / EVENT_VALUE追加
    [ { itemId: '16' },
      { itemId: '223' },
      { itemId: '466' },
      { itemId: '520' },
      { itemId: '529' },
      { itemId: '594' },
      { itemId: '596' },
      { itemId: '708' },
      { itemId: '919' },
      { itemId: '1035' },
      { itemId: '1073' },
      { itemId: '1101' },
      { itemId: '1208' },
      { itemId: '1219' },
      { itemId: '1220' },
      { itemId: '1247' },
      { itemId: '1259' },
      { itemId: '1307' },
      { itemId: '1380' },
      { itemId: '1394' },
      { itemId: '1485' },
      { itemId: '2081' },
      { itemId: '2657' },
      { itemId: '2985' },
      { itemId: '3948' } ]
    
    // Itemデータセットを追加
    [ { itemId: '342' },
      { itemId: '902' },
      { itemId: '968' },
      { itemId: '1028' },
      { itemId: '1079' },
      { itemId: '1086' },
      { itemId: '1094' },
      { itemId: '1228' },
      { itemId: '1244' },
      { itemId: '1247' },
      { itemId: '1258' },
      { itemId: '1269' },
      { itemId: '1304' },
      { itemId: '1394' },
      { itemId: '1682' },
      { itemId: '1947' },
      { itemId: '2352' },
      { itemId: '2359' },
      { itemId: '2396' },
      { itemId: '2502' },
      { itemId: '2987' },
      { itemId: '3481' },
      { itemId: '3504' },
      { itemId: '3809' },
      { itemId: '4027' } ]

    また推論結果が変わりました。

    おわりに

    入力されたデータの内容でレコメンドの結果が見事に変化しました。

    とはいえ今回はidのリストだけを見ているため、どのレコメンドが直感的に合っていそうかをみることはこれだけでは難しいです。

    また、Event Trackingで投入されたデータも加えるとさらに結果が変わっていくことになりますので、いきなり実戦投入するよりは、最小単位から少しずつデータセットを追加・カスタマイズして調整していく形の開発がよさそうかなと思います。

    広告ここから
    広告ここまで
    Home
    Search
    Bookmark