Google BigQueryでお手軽機械学習(BQML)

BigQuery ML(BQML)では

  • 線形回帰
  • ロジスティック回帰
  • k-meansクラスタリング
  • AutoML Tables
  • XGBoost
  • DNN
  • 時系列(ARIMA)

が使える。当初は線形回帰とロジスティック回帰だけだったが今では実用的な手法が増えた。何よりもXGBoostが使えるようになったのが大きい。

XGBoostのメリット

XGBoostは語弊を恐れずに言うと特に何も考えなくてもそれなりの精度が出る、素人でもそこそこのアウトプットを出せてしまう手法である。これまでの線形回帰やロジスティック回帰は前提条件が扱いが難しい手法だった。

XGBoostがお手軽というのは、

  • 正規化不要
  • カテゴリ変数と連続量を意識しなくてもいい
  • 欠損値があってもいい

つまり特徴量の前処理の面倒な部分がかなり軽減されている。与えられた変数を特に加工しなくても使える。たとえばAutoML Tablesはモデル構築時にすべての変数について変数のタイプを指定する必要がある。XGBoostはそういったことが不要な、お手軽で大変便利な手法である。

この記事ではBigQueryでお手軽に機械学習を体感してみようということで、XGBoostを使ってBQMLを説明する。

方法

データセットの準備

対象データは学習(train)/評価(evaluate/validate)/テストで予測するデータに分割する。目的変数と説明変数に加え、分割用の列subsetを作り

  • subset = 'TRAIN': 学習用データ
  • subset = 'EVALUATE': 評価用データ
  • subset = 'TEST': 予測用データ

という値を付与しておく。今回はBigQueryの公開サンプルデータであるbigquery-public-data.ml_datasets.ulb_fraud_detectionを使って不正取引の予測をするモデルを作る。

  • Classが目的変数となる不正取引フラグ
  • 特徴量はV1V28Amount(取引額)。V1V28はオリジナルの特徴量を主成分分析で集約したもの
  • これを学習:評価:テスト=8:1:1で分割する
create or replace table `my-project.test_dataset.ulb_fraud_detection` as
with t1 as (
  select
    row_number() over() id,
    *,
    rand() rnd
  from `bigquery-public-data.ml_datasets.ulb_fraud_detection`
), t2 as (
  select
    * except(rnd),
    case
      when rnd < 0.8 then 'TRAIN'
      when rnd < 0.9 then 'EVALUATE'
      else 'TEST'
    end subset
  from t1
)
select * from t2 order by id;

BQMLの機械学習手順

まずBQMLの操作手順だが、機械学習の手順に沿い

  1. モデルの構築(TRAIN)
  2. モデルの評価(EVALUATE/VALIDATE)
  3. 予測

それぞれに対応したステートメントがある。

MLの処理

モデルの構築

CREATE OR REPLACE MODEL `データセット.モデル名`
TRANSFORM(そのまま使う列名1,
  そのまま使う列名2,
  変換用の関数(列名3) AS 別名3,
  普通の関数でもいい(列名4) AS 別名4)
OPTIONS(MODEL_TYPE = 'モデル名'
  input_label_cols=['目的変数']
  パラメータ名1=値1,
  パラメータ名2=値2) AS
SELECT 使う列名
FROM データのテーブル
WHERE subset = 'TRAIN' -- 学習用データ
;

TRANSFORM()は前処理の指定。TRANSFORMがない場合、SELECTしたテーブルの列がそのまま使われる。
OPTIONS()はモデル自体の指定。モデルの種類やパラメータを指定する。

  1. 学習対象テーブルからデータをSELECT
  2. TRANSFORM()に基づいて前処理(データ加工など)
  3. OPTIONS()に基づいて学習

あらかじめ対象のテーブルに対して前処理を済ませているのであればTRANSFORM()は不要になる。

前処理固有の関数は
https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-preprocessing-functions
を参照。これらはMLでない普通のクエリの中でも使える。

ロジスティック回帰の場合

CREATE OR REPLACE MODEL `my-project.test_dataset.model_fraud_detection_logit_100_iter`
OPTIONS(
  MODEL_TYPE='LOGISTIC_REG',
  INPUT_LABEL_COLS=['Class']
) AS
select * except(id, Time, subset)
from `my-project.test_dataset.ulb_fraud_detection`
where subset = 'TRAIN';

このケースでは特徴量が主成分化されているのでロジスティック回帰が使いやすい。

XGBoostの場合

CREATE OR REPLACE MODEL `my-project.test_dataset.model_fraud_detection_xgb_100_iter`
OPTIONS(
  MODEL_TYPE='BOOSTED_TREE_CLASSIFIER',
  MAX_ITERATIONS=100,
  LEARN_RATE=0.1,
  SUBSAMPLE=0.8,
  INPUT_LABEL_COLS=['Class']
) AS
select * except(id, Time, subset)
from `my-project.test_dataset.ulb_fraud_detection`
where subset = 'TRAIN';

モデルの種類によってOPTIONS()で指定するパラメータが異なる。XGBoostのチューニングパラメータの詳細は以下のページに記載しているが

  • 計算の繰り返し回数(max_iterations):100回
  • 学習率(learn_rate):0.1
  • 木を作る際に用いるレコード数のサンプリング率(subsample):0.8

結果はこのようになる。


モデルの評価

SELECT * FROM ML.EVALUATE(MODEL `データセット.モデル名`, (
  SELECT 使う列名
  FROM データのテーブル
  WHERE subset = 'EVALUATE' -- 評価用データ
));

たとえば

SELECT * FROM ML.EVALUATE(MODEL `my-project.test_dataset.model_fraud_detection_xgb_100_iter`, (
  select * except(id, Time, subset)
  from `my-project.test_dataset.ulb_fraud_detection`
  where subset = 'EVALUATE'
));

予測

SELECT * FROM ML.PREDICT(MODEL `データセット.モデル名`, (
  SELECT 使う列名
  FROM データのテーブル
  WHERE subset = 'TEST' -- テスト用データ
));

たとえば

SELECT * FROM ML.PREDICT(MODEL `my-project.test_dataset.model_fraud_detection_xgb_100_iter`, (
  select * except(id, Time, subset)
  from `my-project.test_dataset.ulb_fraud_detection`
  where subset = 'TEST'
));

true/false予測では以下のように結果から確率を抽出して正解と比較するといい。

with predictions as (
  SELECT * FROM ML.PREDICT(MODEL `my-project.test_dataset.model_fraud_detection_xgb_100_iter`, (
    select * except(id, Time, subset)
    from `my-project.test_dataset.ulb_fraud_detection`
    where subset = 'TEST'
  ))
)
select
  Class,
  (select p.prob from unnest(predictions.predicted_Class_probs) p where p.label = 1) prob
from predictions;

処理時間とコスト

学習データが22万行30列程度の55MBのデータ

100ラウンドの学習で10分/処理したデータ量が16GB

一方で3ラウンドの学習にした場合8分で処理したデータ量は変わらない。

データを前処理するオーバーヘッドが大きいようで、ラウンド数を増やしてもコストはあまり変わらないようである。

評価と予測には時間がかからない。


こんな感じでインスタンスを立てたり面倒な設定をしたりする必要もなく簡単に機械学習を実現できる

データ分析 の記事一覧