行列分解モデルを使用して明示的なフィードバックに基づくレコメンデーションを作成する

このチュートリアルでは、行列分解モデルを作成し、このモデルを movielens1m データセット内のお客様の映画評価データでトレーニングする方法について説明します。その後、行列分解モデルを使用して、ユーザーにおすすめの映画を生成します。

お客様提供の評価を使用してモデルをトレーニングすることを、明示的なフィードバックによるトレーニングと呼びます。明示的なフィードバックをトレーニング データとして使用する場合、行列分解モデルは交互最小二乗アルゴリズムによりトレーニングされます。

データセットを作成する

ML モデルを保存する BigQuery データセットを作成します。

コンソール

  1. Google Cloud コンソールで、[BigQuery] ページに移動します。

    [BigQuery] ページに移動

  2. [エクスプローラ] ペインで、プロジェクト名をクリックします。

  3. [アクションを表示] > [データセットを作成] をクリックします。

  4. [データセットを作成する] ページで、次の操作を行います。

    • [データセット ID] に「bqml_tutorial」と入力します。

    • [ロケーション タイプ] で [マルチリージョン] を選択してから、[US(米国の複数のリージョン)] を選択します。

    • 残りのデフォルトの設定は変更せず、[データセットを作成] をクリックします。

bq

新しいデータセットを作成するには、--location フラグを指定した bq mk コマンドを使用します。使用可能なパラメータの一覧については、bq mk --dataset コマンドのリファレンスをご覧ください。

  1. データの場所が US に設定され、BigQuery ML tutorial dataset という説明の付いた、bqml_tutorial という名前のデータセットを作成します。

    bq --location=US mk -d \
     --description "BigQuery ML tutorial dataset." \
     bqml_tutorial

    このコマンドでは、--dataset フラグの代わりに -d ショートカットを使用しています。-d--dataset を省略した場合、このコマンドはデフォルトでデータセットを作成します。

  2. データセットが作成されたことを確認します。

    bq ls

API

定義済みのデータセット リソースを使用して datasets.insert メソッドを呼び出します。

{
  "datasetReference": {
     "datasetId": "bqml_tutorial"
  }
}

BigQuery DataFrames

このサンプルを試す前に、BigQuery DataFrames を使用した BigQuery クイックスタートの手順に沿って BigQuery DataFrames を設定してください。詳細については、BigQuery DataFrames のリファレンス ドキュメントをご覧ください。

BigQuery に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の ADC の設定をご覧ください。

import google.cloud.bigquery

bqclient = google.cloud.bigquery.Client()
bqclient.create_dataset("bqml_tutorial", exists_ok=True)

Movielens データをアップロードする

movielens1m データを BigQuery にアップロードします。

CLI

bq コマンドライン ツールを使用して movielens1m データをアップロードする手順は次のとおりです。

  1. Cloud Shell を開きます。

    Cloud Shell をアクティブにする

  2. 評価データを ratings テーブルにアップロードします。コマンドラインで次のクエリを貼り付け、Enter キーを押します。

    curl -O 'http://files.grouplens.org/datasets/movielens/ml-1m.zip'
    unzip ml-1m.zip
    sed 's/::/,/g' ml-1m/ratings.dat > ratings.csv
    bq load --source_format=CSV bqml_tutorial.ratings ratings.csv \
      user_id:INT64,item_id:INT64,rating:FLOAT64,timestamp:TIMESTAMP
    
  3. 映画データを movies テーブルにアップロードします。コマンドラインで次のクエリを貼り付け、Enter キーを押します。

    sed 's/::/@/g' ml-1m/movies.dat > movie_titles.csv
    bq load --source_format=CSV --field_delimiter=@ \
    bqml_tutorial.movies movie_titles.csv \
    movie_id:INT64,movie_title:STRING,genre:STRING
    

BigQuery DataFrames

このサンプルを試す前に、BigQuery DataFrames を使用した BigQuery クイックスタートの手順に沿って BigQuery DataFrames を設定してください。詳細については、BigQuery DataFrames のリファレンス ドキュメントをご覧ください。

BigQuery に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の ADC を設定するをご覧ください。

まず、bqclient = google.cloud.bigquery.Client() を使用して Client オブジェクトを作成します。次に、前の手順で作成したデータセットに movielens1m データを読み込みます。

import io
import zipfile

import google.api_core.exceptions
import requests

try:
    # Check if you've already created the Movielens tables to avoid downloading
    # and uploading the dataset unnecessarily.
    bqclient.get_table("bqml_tutorial.ratings")
    bqclient.get_table("bqml_tutorial.movies")
except google.api_core.exceptions.NotFound:
    # Download the https://grouplens.org/datasets/movielens/1m/ dataset.
    ml1m = requests.get("http://files.grouplens.org/datasets/movielens/ml-1m.zip")
    ml1m_file = io.BytesIO(ml1m.content)
    ml1m_zip = zipfile.ZipFile(ml1m_file)

    # Upload the ratings data into the ratings table.
    with ml1m_zip.open("ml-1m/ratings.dat") as ratings_file:
        ratings_content = ratings_file.read()

    ratings_csv = io.BytesIO(ratings_content.replace(b"::", b","))
    ratings_config = google.cloud.bigquery.LoadJobConfig()
    ratings_config.source_format = "CSV"
    ratings_config.write_disposition = "WRITE_TRUNCATE"
    ratings_config.schema = [
        google.cloud.bigquery.SchemaField("user_id", "INT64"),
        google.cloud.bigquery.SchemaField("item_id", "INT64"),
        google.cloud.bigquery.SchemaField("rating", "FLOAT64"),
        google.cloud.bigquery.SchemaField("timestamp", "TIMESTAMP"),
    ]
    bqclient.load_table_from_file(
        ratings_csv, "bqml_tutorial.ratings", job_config=ratings_config
    ).result()

    # Upload the movie data into the movies table.
    with ml1m_zip.open("ml-1m/movies.dat") as movies_file:
        movies_content = movies_file.read()

    movies_csv = io.BytesIO(movies_content.replace(b"::", b"@"))
    movies_config = google.cloud.bigquery.LoadJobConfig()
    movies_config.source_format = "CSV"
    movies_config.field_delimiter = "@"
    movies_config.write_disposition = "WRITE_TRUNCATE"
    movies_config.schema = [
        google.cloud.bigquery.SchemaField("movie_id", "INT64"),
        google.cloud.bigquery.SchemaField("movie_title", "STRING"),
        google.cloud.bigquery.SchemaField("genre", "STRING"),
    ]
    bqclient.load_table_from_file(
        movies_csv, "bqml_tutorial.movies", job_config=movies_config
    ).result()

モデルを作成する

行列分解モデルを作成し、ratings テーブルのデータをトレーニングします。このモデルは、お客様が提供した映画の評価に基づいて、すべてのユーザー / アイテムペアの評価を予測するようにトレーニングされています。

SQL

次の CREATE MODEL ステートメントは、これらの列を使用してレコメンデーションを生成します。

  • user_id - ユーザー ID。
  • item_id - 映画 ID。
  • rating - ユーザーが該当項目に付けた 1~5 の明示的な評価。

次の手順でモデルを作成します。

  1. Google Cloud コンソールで、[BigQuery] ページに移動します。

    [BigQuery] に移動

  2. クエリエディタに次のクエリを貼り付け、[実行] をクリックします。

    CREATE OR REPLACE MODEL `bqml_tutorial.mf_explicit`
    OPTIONS (
      MODEL_TYPE = 'matrix_factorization',
      FEEDBACK_TYPE = 'explicit',
      USER_COL = 'user_id',
      ITEM_COL = 'item_id',
      L2_REG = 9.83,
      NUM_FACTORS = 34)
    AS
    SELECT
    user_id,
    item_id,
    rating
    FROM `bqml_tutorial.ratings`;

    クエリが完了するまでに約 10 分かかります。完了後、mf_explicit モデルが [エクスプローラ] ペインに表示されます。クエリは CREATE MODEL ステートメントを使用してモデルを作成するため、クエリの結果は表示されません。

BigQuery DataFrames

このサンプルを試す前に、BigQuery DataFrames を使用した BigQuery クイックスタートの手順に沿って BigQuery DataFrames を設定してください。詳細については、BigQuery DataFrames のリファレンス ドキュメントをご覧ください。

BigQuery に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の ADC の設定をご覧ください。

from bigframes.ml import decomposition
import bigframes.pandas as bpd

# Load data from BigQuery
bq_df = bpd.read_gbq(
    "bqml_tutorial.ratings", columns=("user_id", "item_id", "rating")
)

# Create the Matrix Factorization model
model = decomposition.MatrixFactorization(
    num_factors=34,
    feedback_type="explicit",
    user_col="user_id",
    item_col="item_id",
    rating_col="rating",
    l2_reg=9.83,
)
model.fit(bq_df)
model.to_gbq(
    your_model_id, replace=True  # For example: "bqml_tutorial.mf_explicit"
)

コードが完了するまでに約 10 分かかります。完了後、mf_explicit モデルが [エクスプローラ] ペインに表示されます。

トレーニングの統計情報を取得する

必要に応じて、Google Cloud コンソールでモデルのトレーニング統計情報を表示できます。

ML アルゴリズムがモデルを構築するには、さまざまなパラメータを使用してモデルのイテレーションを多数作成し、損失を最小限に抑えるモデルのバージョンを選択します。このプロセスを経験損失最小化と呼びます。モデルのトレーニング統計情報で、モデルの各反復処理に関連付けられた損失を確認できます。

モデルのトレーニング統計情報を表示する手順は次のとおりです。

  1. Google Cloud コンソールで、[BigQuery] ページに移動します。

    BigQuery に移動

  2. 左側のペインで、 [エクスプローラ] をクリックします。

    エクスプローラ ペインのボタンがハイライト表示されている。

    左側のペインが表示されていない場合は、 左側のペインを開くをクリックしてペインを開きます。

  3. [エクスプローラ] ペインで、プロジェクトを開き、[データセット] をクリックして、bqml_tutorial データセットをクリックします。

  4. [モデル] タブをクリックします。

  5. mf_explicit モデルをクリックし、[トレーニング] タブをクリックします。

  6. [表示形式] セクションで、[テーブル] をクリックします。結果は次のようになります。

    +-----------+--------------------+--------------------+
    | Iteration | Training Data Loss | Duration (seconds) |
    +-----------+--------------------+--------------------+
    |  11       | 0.3943             | 42.59              |
    +-----------+--------------------+--------------------+
    |  10       | 0.3979             | 27.37              |
    +-----------+--------------------+--------------------+
    |   9       | 0.4038             | 40.79              |
    +-----------+--------------------+--------------------+
    |  ...      | ...                | ...                |
    +-----------+--------------------+--------------------+
    

    [トレーニング データの損失] 列は、モデルのトレーニング後に計算された損失指標を表します。これは行列分解モデルであるため、この列には平均二乗誤差が表示されます。

ML.TRAINING_INFO 関数を使用して、モデルのトレーニング統計情報を確認することもできます。

モデルを評価する

モデルから返された予測映画評価をトレーニング データの実際のユーザー映画評価と比較して、モデルのパフォーマンスを評価します。

SQL

ML.EVALUATE 関数を使用してモデルを評価します。

  1. Google Cloud コンソールで、[BigQuery] ページに移動します。

    [BigQuery] に移動

  2. クエリエディタに次のクエリを貼り付け、[実行] をクリックします。

    SELECT
    *
    FROM
    ML.EVALUATE(
      MODEL `bqml_tutorial.mf_explicit`,
      (
        SELECT
          user_id,
          item_id,
          rating
        FROM
          `bqml_tutorial.ratings`
      ));

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

    +---------------------+---------------------+------------------------+-----------------------+--------------------+--------------------+
    | mean_absolute_error | mean_squared_error  | mean_squared_log_error | median_absolute_error |      r2_score      | explained_variance |
    +---------------------+---------------------+------------------------+-----------------------+--------------------+--------------------+
    | 0.48494444327829156 | 0.39433706592870565 |   0.025437895793637522 |   0.39017059802629905 | 0.6840033369412044 | 0.6840033369412264 |
    +---------------------+---------------------+------------------------+-----------------------+--------------------+--------------------+
    

    評価結果における重要な測定指標は、R2スコア(決定係数)です。R2 スコアは、線形回帰予測が実際のデータに近似するかどうかを決定する統計的尺度です。0 の値は、モデルの平均値周辺のレスポンス データにばらつきがないことを示しています。1 の値は、モデルの平均値周辺のレスポンス データにばらつきがあることを示しています。

    ML.EVALUATE 関数の出力の詳細については、出力をご覧ください。

また、入力データを指定せずに ML.EVALUATE を呼び出すこともできます。これにはトレーニング中に計算された評価指標が使用されます。

BigQuery DataFrames

このサンプルを試す前に、BigQuery DataFrames を使用した BigQuery クイックスタートの手順に沿って BigQuery DataFrames を設定してください。詳細については、BigQuery DataFrames のリファレンス ドキュメントをご覧ください。

BigQuery に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の ADC を設定するをご覧ください。

model.score() を呼び出してモデルを評価します。

# Evaluate the model using the score() function
model.score(bq_df)
# Output:
# mean_absolute_error	mean_squared_error	mean_squared_log_error	median_absolute_error	r2_score	explained_variance
# 0.485403	                0.395052	        0.025515	            0.390573	        0.68343	        0.68343

ユーザー / アイテムペアのサブセットの予測評価を取得する

5 人のユーザーが各映画に付けた評価の予測値を取得します。

SQL

ML.RECOMMEND 関数を使用して予測評価を取得します。

  1. Google Cloud コンソールで、[BigQuery] ページに移動します。

    [BigQuery] に移動

  2. クエリエディタに次のクエリを貼り付け、[実行] をクリックします。

    SELECT
    *
    FROM
    ML.RECOMMEND(
      MODEL `bqml_tutorial.mf_explicit`,
      (
        SELECT
          user_id
        FROM
          `bqml_tutorial.ratings`
        LIMIT 5
      ));

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

    +--------------------+---------+---------+
    | predicted_rating   | user_id | item_id |
    +--------------------+---------+---------+
    | 4.2125303962491873 | 4       | 3169    |
    +--------------------+---------+---------+
    | 4.8068920531981263 | 4       | 3739    |
    +--------------------+---------+---------+
    | 3.8742203494732403 | 4       | 3574    |
    +--------------------+---------+---------+
    | ...                | ...     | ...     |
    +--------------------+---------+---------+
    

BigQuery DataFrames

このサンプルを試す前に、BigQuery DataFrames を使用した BigQuery クイックスタートの手順に沿って BigQuery DataFrames を設定してください。詳細については、BigQuery DataFrames のリファレンス ドキュメントをご覧ください。

BigQuery に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の ADC を設定するをご覧ください。

model.predict() を呼び出して予測評価を取得します。

# Use predict() to get the predicted rating for each movie for 5 users
subset = bq_df[["user_id"]].head(5)
predicted = model.predict(subset)
print(predicted)
# Output:
#   predicted_rating	user_id	 item_id	rating
# 0	    4.206146	     4354	  968	     4.0
# 1	    4.853099	     3622	  3521	     5.0
# 2	    2.679067	     5543	  920	     2.0
# 3	    4.323458	     445	  3175	     5.0
# 4	    3.476911	     5535	  235	     4.0

レコメンデーションを生成する

予測評価を使用して、各ユーザー向けに上位 5 つのおすすめ映画を生成します。

SQL

レコメンデーションを生成する手順は次のとおりです。

  1. Google Cloud コンソールで、[BigQuery] ページに移動します。

    [BigQuery] に移動

  2. 予測評価をテーブルに書き込みます。クエリエディタに次のクエリを貼り付け、[実行] をクリックします。

    CREATE OR REPLACE TABLE `bqml_tutorial.recommend`
    AS
    SELECT
    *
    FROM
    ML.RECOMMEND(MODEL `bqml_tutorial.mf_explicit`);
  3. 予測評価を映画情報と結合し、ユーザーごとに上位 5 件の結果を選択します。クエリエディタに次のクエリを貼り付け、[実行] をクリックします。

  SELECT
    user_id,
    ARRAY_AGG(STRUCT(movie_title, genre, predicted_rating) ORDER BY predicted_rating DESC LIMIT 5)
  FROM
    (
      SELECT
        user_id,
        item_id,
        predicted_rating,
        movie_title,
        genre
      FROM
        `bqml_tutorial.recommend`
      JOIN
        `bqml_tutorial.movies`
        ON
          item_id = movie_id
    )
  GROUP BY
    user_id;

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

  +---------+-------------------------------------+------------------------+--------------------+
  | user_id | f0_movie_title                      | f0_genre               | predicted_rating   |
  +---------+-------------------------------------+------------------------+--------------------+
  | 4597    | Song of Freedom (1936)              | Drama                  | 6.8495752907364009 |
  |         | I Went Down (1997)                  | Action/Comedy/Crime    | 6.7203235758772877 |
  |         | Men With Guns (1997)                | Action/Drama           | 6.399407352232001  |
  |         | Kid, The (1921)                     | Action                 | 6.1952890198126731 |
  |         | Hype! (1996)                        | Documentary            | 6.1895766097451475 |
  +---------+-------------------------------------+------------------------+--------------------+
  | 5349    | Fandango (1985)                     | Comedy                 | 9.944574012151549  |
  |         | Breakfast of Champions (1999)       | Comedy                 | 9.55661860430112   |
  |         | Funny Bones (1995)                  | Comedy                 | 9.52778917835076   |
  |         | Paradise Road (1997)                | Drama/War              | 9.1643621767929133 |
  |         | Surviving Picasso (1996)            | Drama                  | 8.807353289233772  |
  +---------+-------------------------------------+------------------------+--------------------+
  | ...     | ...                                 | ...                    | ...                |
  +---------+-------------------------------------+------------------------+--------------------+
  

BigQuery DataFrames

このサンプルを試す前に、BigQuery DataFrames を使用した BigQuery クイックスタートの手順に沿って BigQuery DataFrames を設定してください。詳細については、BigQuery DataFrames のリファレンス ドキュメントをご覧ください。

BigQuery に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の ADC を設定するをご覧ください。

model.predict() を呼び出して予測評価を取得します。

# import bigframes.bigquery as bbq

# Load movies
movies = bpd.read_gbq("bqml_tutorial.movies")

# Merge the movies df with the previously created predicted df
merged_df = bpd.merge(predicted, movies, left_on="item_id", right_on="movie_id")

# Separate users and predicted data, setting the index to 'movie_id'
users = merged_df[["user_id", "movie_id"]].set_index("movie_id")

# Take the predicted data and sort it in descending order by 'predicted_rating', setting the index to 'movie_id'
sort_data = (
    merged_df[["movie_title", "genre", "predicted_rating", "movie_id"]]
    .sort_values(by="predicted_rating", ascending=False)
    .set_index("movie_id")
)

# re-merge the separated dfs by index
merged_user = sort_data.join(users, how="outer")

# group the users and set the user_id as the index
merged_user.groupby("user_id").head(5).set_index("user_id").sort_index()
print(merged_user)
# Output:
# 	            movie_title	                genre	        predicted_rating
# user_id
#   1	    Saving Private Ryan (1998)	Action|Drama|War	    5.19326
#   1	        Fargo (1996)	       Crime|Drama|Thriller	    4.996954
#   1	    Driving Miss Daisy (1989)	    Drama	            4.983671
#   1	        Ben-Hur (1959)	       Action|Adventure|Drama	4.877622
#   1	     Schindler's List (1993)	   Drama|War	        4.802336
#   2	    Saving Private Ryan (1998)	Action|Drama|War	    5.19326
#   2	        Braveheart (1995)	    Action|Drama|War	    5.174145
#   2	        Gladiator (2000)	      Action|Drama	        5.066372
#   2	        On Golden Pond (1981)	     Drama	            5.01198
#   2	    Driving Miss Daisy (1989)	     Drama	            4.983671