BigQuery ML でボストン住宅価格予測
Cloud Nextで発表されたBigQuery MLを使って、ボストン住宅価格予測をやってみます。
BigQuery ML
Cloud Next’18 のKeynoteで発表された、BigQueryのSQLクエリ内で機械学習モデルの学習/推論ができる機能です。 ドキュメントはこちら
特徴としては、
- BigQuery内で機械学習モデルの学習&推論ができる機能
- 学習、推論コードはすべてSQL
- 学習、推論用のデータはBigQuery内のデータで行う。
- model_typeとして指定できるのは、今の所下記の2つ
- linear_reg
- logistic_reg
- 学習モデルはBQ内に永続化され、モデル自体のダウンロードは(今の所)できない
モデルが2種類しかないのですが、とりあえず試す分には問題ないでしょう。 今後追加実装もされるようです。
データセットの準備
scikit-learnに含まれる、Boston house-pricesのデータセットを使います。 データセットの詳細はこちらを参考にしています。
今回、下記のPythonパッケージを使います
- scikit-learn
- pandas
- pands-gbq
import pandas as pd from sklearn.datasets import load_boston from sklearn.model_selection import train_test_split boston = load_boston() X = pd.DataFrame(boston.data, columns=boston.feature_names) display(X) y = pd.DataFrame(boston.target, columns=['price']) display(y)
scikit-learnで予測
比較のために、scikit-learnで予測してみます。
from sklearn.linear_model import LinearRegression (X_train, X_test, y_train, y_test) = train_test_split(X, y, test_size=0.1, random_state=0) model = LinearRegression() model.fit(X_train, y_train) predicted = model.predict(X_train)[:, 0] result = y_train.copy() result['predicted'] = predicted result.sort_index().plot()
import sklearn result = y_test.copy() predicted = model.predict(X_test)[:, 0] result['predicted'] = predicted result.sort_index().plot() "score: %s" % (sklearn.metrics.regression.r2_score(result['price'], result['predicted']))
'score: 0.5151316073718609'
今回は精度とか気にしないのでこれでいいでしょう。
BigQueryへのデータセット投入
先程のデータセットをBQに投入します。特徴量と正解値を同じテーブルに入れたほうがラクなので、 DataFrame上で結合してから、BigQuery APIで入れちゃいます。
また、あらかじめtest_dataset
という名前でBigQuery データセットを作成してあります。
PROJECT_ID = XXXX # GCPプロジェクトID train_data = X_train.copy() train_data['price'] = y_train train_data test_data = X_test.copy() test_data['price'] = y_test test_data train_data.to_gbq("test_dataset.boston_train", PROJECT_ID) test_data.to_gbq("test_dataset.boston_test", PROJECT_ID)
BigQuery ML
学習
データの準備ができたので、BigQuery MLで、さっそくモデルを学習させてみます。
以下のSQLを打てば、BQで学習が始まります。
CREATE OR REPLACE MODEL `test_dataset.boston_predict_model` OPTIONS (model_type='linear_reg', input_label_cols=['price']) AS SELECT * FROM `test_dataset.boston_train`
CREATE OR REPLACE MODEL
でモデルを作成します。モデル名は [dataset].[model name]
と指定します。
OPTIONS
ではモデルの設定が可能です。ここではモデルとしてlinear_reg
、また正解データのラベルは作成したデータ・セットのprice
を指定しています。
学習用のデータはSELECT XXX
で指定します。テーブルには特徴量と正解ラベルが一緒に入っているので、BQが区別できるよう、input_label_colsで正解データの列を指定しているわけです。
学習が成功すると、モデルが作成されます。
BQのUIから見ると、データセット内に、テーブルと同じように格納されていることがわかります。
評価
ML.TRAINING_INFO
で学習の収束状況などを確認できます。
SELECT * FROM ML.TRAINING_INFO(MODEL `test_dataset.boston_predict_model`)
また、ML.EVALUATEでモデルの評価もできます。
SELECT * FROM ML.EVALUATE(MODEL `soymsk-gcp.test_dataset.boston_predict_model`, ( SELECT * FROM `test_dataset.boston_test`))
結構lossが大きいようですが、iteration回数は調整できるので、今回はこのままいきます。
ちなみに、データを入れる際にラベルを指定していませんが、ラベルはModel側が記憶しているので、特に指定する必要はありません。逆に、学習時と同じラベル(カラム名)でデータを入れる必要があります。
推論
学習済みのモデルを使った推論もSQLクエリで行います。
SELECT price, predicted_price FROM ML.PREDICT(MODEL `soymsk-gcp.test_dataset.boston_predict_model`, ( SELECT * FROM `test_dataset.boston_test`))
ML.PREDICTの第一引数に学習済みモデルをMODEL [model name]
の形式で指定し、第2引数に特徴量を入れます。ここでは先程作成したboston_testテーブルのデータを入れています。
カラム名も同じなため、改めて指定し直す必要もありません。
精度はチューニングしていないのでそれほど良くはありませんが、SQLクエリだけでMLモデルを作って推論することができました。
BigQuery MLの価格
ここが気になるところですが、ドキュメントには
Currently, if you use BigQuery on demand, your BigQuery ML charges are based on the data processed by each query. For BigQuery ML queries, the data processed is usually greater than the just the input data for the CREATE MODEL statement. Flat-rate customers can use their existing slots for BigQuery ML until Jul 31, 2019.
とあるので、他のSQLクエリ同様、処理データ量に依存するみたいです。
が、書いてあるとおり、処理データ > 全データ量
となる場合もあるらしく、反復計算するので当たり前といえばそうですが、ここは気にしておいたほうが良さそうです。
なんとなく 「全データ量 x itreration数」が上限だと予想しますが、そもそも価格ロジック自体がまだβであり、将来的に変更となる可能性があります。
まとめ
今回BQで簡単な線形回帰をやってみました。 簡単なモデルしか用意されていないですが、BigQuery上に大規模なデータセットを持っている場合、いちいちSparkML等でやるのも骨が折れますが、BigQueryのマシンリソースを使って誰でも簡単に機械学習が試せる、というのはすごいことだと思います。
個人的には時系列予測や異常検知系のニーズが高いので、そこが実装されると異常検知しつつStackdriver経由でアラートあげるとか、普通にやるといろいろなコンポーネントを組み合わせないと実現できない構成がぐっとラクに作れるようになるのではと期待しています。