BQML blocksを使ってLookerでBQMLしましょう

※ 本投稿はLooker Advent Caledar 2021 22日目の記事です。

年末にお小遣い稼ぎをしようと、株を買ってみようとしたんですが、せっかくなのでLookerでBQMLを使って予測した結果を元に売り買いしてみようじゃないかというのが動機です。(良い子は絶対マネしないように)

今回は、特定の株価がある時点でいくらになっているかというのを予測します。予測に使う株は伊藤ハムです。筆者は肉を食べないのですが、伊藤ハムから出た大豆ミートのチキンナゲットが本当においしかったので、将来伸びるかなという期待を込めて選定しました。

前置きはこんなところで、どうやってやるかを説明します。

今年、Lookerのマーケットプレイスにて、BQML blocksが登場しました。今回はこちらをカスタマイズして使っていきたいと思います。


このblocksの作りとしては、BQMLのモデルを作るところや、予測等を動かすためのSQL(CREATE MODELやML PRDICT等)はすでにblocksで書かれているので、カスタマイズするのは、あくまでトレーニングデータを作る部分のみになります。
このBlocksのLookMLは独特な作りをしているので、初見だと取っ付きにくい印象ですが、Exploreの画面で、フィールドを順番どおりにクリックしていくだけで、予測ができるようなユーザフレンドリーな仕様になっています。

始める前に前提条件があります。

  • サービスアカウントにBigQuery Data Editor および BigQuery Job User predefined rolesが適用されていること

  • LookerPDTが今回使用するデータベース接続の設定で有効化されていること

  • PDTはデータベース接続時に設定したtemp datasetに作成されていきます。その際、元のデータが格納されているデータセットのRegionと、このtemp datasetのRegionは必ず同じである必要があります。
    例えば、このblocksにすでにサンプルとして定義されているGA360のパブリックデータですが、このデータはUS Regionに入っているので、このtemp schemaもUSで作成する必要があります

今回は、株価の予測なので、BigQuery ML Time-series Forecasting (ARIMA)モデルを使います。各モデルによって、blocksが分かれるので、用途に応じてインストールしてください。

カスタマイズの仕方

  1. Marketplaceからのインストールすると、プロジェクトの中に、
    - imported projects
    - arima_model_info.model/google_analytics_forecast.model(read-only)
    - refinements.lkml
    - manifest.lkml

         が入っています。初期状態では、GA360のパブリックデータを元に、Forcastができる状態になっています。imported projectsの中をざっくり説明すると、
     
           input_data.viewがトレーニングに使用するデータを抽出する用

          それ以外のviewはBQMLのクエリを作るのに使う用(基本的には触りません)
     

  1. 今回は、株価予測をしたいので、このユースケース専用のフォルダを作成し、また専用のモデルファイル、explore、input_data.viewを作成していきます。
    28a65b4d-a1fd-4fd8-8307-183baf29eff2.png
    フォルダ構成

    stock_price_forcast.model 中身

    connection: "my_stockdata"

    include: "*.view.lkml"
    include: "//bqml-arima/explores/bqml_arima.explore"
    include: "model_name_suggestions.explore"

    explore: ito_ham_stock_price_prediction {
    label: "BQML ARIMA Plus: Itoham stock price ARIMA"
    description: "Use this Explore to create BQML ARIMA Plus models to forecast stock price for itoham"

    extends: [bqml_arima]

    join: arima_forecast {
    type:full_outer
    relationship: one_to_one
    sql_on: ${input_data.date} = ${arima_forecast.forecast_date} ;;
    }
    }

    input_data.view 中身 

    include: "//bqml-arima/**/input_data.view"

    view: +input_data {
    label: "[1] BQML: Input Data"

    derived_table: {
    sql:
    SELECT
    (stock_2296._date_ ) AS stock_2296__date__date,
    stock_2296.close AS stock_2296_m_close,
    nzd_jpy_kawase.close/(LEAD(nzd_jpy_kawase.close) OVER (ORDER BY stock_2296._date_ DESC))-1 AS kawase_prev_change,
    stock_2296.close/(LEAD(stock_2296.close) OVER (ORDER BY stock_2296._date_ DESC))-1 AS ito_ham_prev_change
    FROM `rie-playground.market_data.stock_2296` AS stock_2296
    INNER JOIN `rie-playground.market_data.nzd_jpy_kawase` AS nzd_jpy_kawase ON stock_2296._date_ = nzd_jpy_kawase._date_
    ORDER by 1 desc
    ;;
    }

    dimension: date {
    #primary_key: yes
    type: date
    datatype: date
    sql: ${TABLE}.stock_2296__date__date ;;
    }

    dimension: stock_2296_m_close {
    type: number
    sql: ${TABLE}.stock_2296_m_close ;;
    }

    dimension: kawase_prev_change {
    type: number
    sql: ${TABLE}.kawase_prev_change ;;
    }

    dimension: ito_ham_prev_change {
    type: number
    sql: ${TABLE}.ito_ham_prev_change ;;
    }

    dimension: total_visits {
    hidden: yes
    }

    dimension: total_new_visits {
    hidden: yes
    }

    dimension: total_pageviews {
    hidden: yes
    }

    dimension: total_hits {
    hidden: yes
    }

    dimension: total_bounces {
    hidden: yes
    }

    dimension: total_time_on_site {
    hidden: yes
    }

    dimension: total_transactions {
    hidden: yes
    }

    dimension: total_transaction_revenue {
    hidden: yes
    }
    }

    exploreは、元のblocksにあるものをextendsして、forcastとinput_data部分の条件を上書きしています。

    Input_data.viewは元のblocksにあるものをrefinementsして、元のinput_dataにあった不必要なフィールドはhiddenしています。

       

ここで、トレーニングデータとして何を入れるか、結構考えました。むやみにデータを入れても、いい予測はできないので、データを一旦調べてから、予測に役に立ちそうなfeatureを見つけてあげる工程が発生します。いろいろ試行錯誤して、一旦、伊藤ハムの各日の終値と、前日からの終値の変化率、NZD/JPY為替の前日終値からの変化率を使うことにしました、伊藤ハムがニュージーランドあたりで輸入輸出を行っているため、為替の状況に業績が影響することと、為替の動向が株価の変化に先行しているように見えたのでこれでやってみます。なんとなくファンダメンタルとテクニカルがごっちゃになっていますが、お遊びなのでツッコミは受け付けません〜

このマーケットデータですが、日毎の4本値データであれば、investing.comからcsvダウンロードができます。APIはないので、今回みたいなone-offのプロジェクトだったらまぁ人力でいいかという感じです。

  1. model_name_suggestions.exploreのカスタマイズ

    model_name_suggestions.explore 中身
include: "//bqml-arima/**/model_name_suggestions.explore"

explore: +model_name_suggestions {
sql_always_where: ${model_info.explore} ='ito_ham_stock_price_prediction';;
}

sql_always_whereの右辺を先程作成したexplore名を指定します。
このblocksでは、以前使用されたモデルをフィルタから選ばせたり、フィルタの部分から新しいモデル名をインプットして、作成するといったことができます。この今までに作成されたモデルは、BQML_ARIMA_MODEL_INFOのテーブルに保存されており、suggetionもここから作成されます。

 

これで準備ができたので早速予測してみます!

Exploreのフィールドピッカー(左側のフィールド選ぶところのことです)の各ビューに番号が振られているので、素直にこの順番で操作していきます。

  1. モデル作成
    a) まず、[1] input dataから、トレーニングに使用するフィールドを選んでクエリします             2011年からのマーケットデータを使っているので、行制限を5000行に変えました
    b) 次に、[2] Name your modelから、今回は初めてモデル作成するので、モデルの名前を入力します

    G8g5DOjOm8nAng7r_qUNPJeFx5wfP5xWEp06snpoUQRz7v016X6yHH_SJYlfw9bDpECXjIzVPFCGotNBJwmXUNYxtII3os1MKoE4doIaPvSTKOxC5VMNE4UqH-9xMjRtImU06_ULKQ
  2. [3] Select Training Dataから、モデル作成に必要な、time fieldおよび、予測したい対象のフィールドを設定します。こちらも、フィルターの候補のところに、input_dataのviewで作成したフィールドのリストが出てくるので、選ぶだけでOKです。今回は、伊藤ハムの終値を予測したいので、終値を選びます。
    ZpkbbvJ1AXrLLw3oQALQ5anBdVkVWwspAF1C90x25u5o71oHZdxbHq-kkvsjemqrgt44NXitCcMinC6T7g2Pj-FCTkHftgIEaMkSYJBjzSHDrzUX7ErBHWqpQ0h2Iv2zEr9JjspUlA
  3. [4] Set Model Parametersから、必須ではないですが、どれぐらい先を予測するのか、また休日効果を適用する場合のカレンダーを選ぶことができます。1000日も必要ないので、一旦300にして、休日効果はなしで設定します。
    c_sdNicKfz1kUDYMV1IXLbDV7dhLcUfMH4ElS8H1_f8HflWLgaiqT1Dmu7f11AEkjWTjWVwicwgYneDmgRoQ_m6FG-8CZAqbyqDxDkdXpHuQtSB7NFKv74qOX_Md8HWH428kykvWpA

     
  4. これで、モデル作成に必要な情報が用意できたので、[5] Create Model のTrain Modelのdimensionを選んで、最後に実行します。ここで初めて裏側で、BQMLのモデル作成、トレーニングのSQLが構築され、実行されます。(SQLタブ)
    fhPThCaRGmYcps-N-d8TpEL2Y1ARFCwa0UUlF9blmbQ_og7pjvRKmJUOTCYmdzczKH5jqRLogPzQa98uOPFKHdh1GBG4L-5x9Y4r5UUAFW9_m8pYDjBY3KA1s3goo9ruicqa4KsvQw

     

    完了すると、先程追加したTrain Modelのdimensionに'Completed'の文字が出現するので、わかりやすいですね。28.6sかかっています。
    RlnaGz-SGVABMTbImOXkadnFfpDAYyiOo1Ny8MTs9G-6gMlwZfouUkCp-WhRFbb6QZbXsZeeHetFlAhOls30-3nNg3GHm-MaZAtDJE4_DzP7VGraIGn5SBWm1IYhcyRPYZndO23kxw

    5. 作成したモデルの評価(1)

    [6] Evaluation Metricsにて、各評価メトリクスを見ることができます
    hpIYTw_KGVhoGz9ewTzNfY7ySmhiMICsLTJJailnwUHud7ZQgMmJ67BSYOD6EQh942THN_C3emBWK6kEXtJdwXtmsEWHjJ1Bj22qo5lwHUQ2P8SrzXTRdtQB_bxJPOpLmtXxH3pGAA

    6. 作成したモデルの評価(2)

    [9] ARIMA Coefficientsから、モデルの係数を確認します
    n-gZ81kp3bllgyikihMuh9oT2qBgBJtLclnZC4_PlEpMIYJwJey0mVs7ajWCJTBh6UuWddxtGYGkZ5M72t1rih07GSl8NIyofNUWHb6YGCQJSqfxFzPprLQMO6QWhDLUI7AG_6xyEg

    7. そして、最後に予測した値を見てみましょう!

    [7] Forecastから、Forecast dateと予測値のupper bound/lower bound、実際の予測値を出してみます。また今回は信頼度レベル90%、30日分の結果を見てみます。
    mQpJoHyTeGANjLVhZ2w5WDDziX23rPUBaktlJ78JCyaBQEHev1b6Ai1EtKHrFlnHVZJfQwt74Bs6ZEqNKZNxCJ_cUljGkKMFVgLlNgCnhxQLq0yEGfzl0fyuyO81zXDfyh236llh9g
    こんな感じになりました。こんなにフラットになるかしらという感じですが、この記事が日の目を見る12月22日の株価は643.8だそうです。執筆時点(12/1)の終値は、633だったので、上がるだろうってことでとりあえず買ってみてもよさそうです。

    この記事をアップロードする前日の21日の終値は649だったので、約5円ぐらいの差分でした。ちなみに、シンプルに伊藤ハムの終値だけを使って予測した場合は、21日の予測は637円だったのでちょっと精度が落ちます。


     

まとめ

 なんだか個人のブログみたいな内容になってしまいましたが、

 LookerでBQMLを扱うところがすごく簡単になりました!

 っていうところと、

 BQMLはunivariateだから、いろいろな要素が絡む株価の予測にはあまり向いてないんじゃと個人的に  思っています。機械学習路線で予測するのだとしたら、TensorFlowとか使った方が望みがありそうなので、そちらにチャレンジしてみたいと思います。

3 0 387
0 REPLIES 0
Top Labels in this Space
Top Solution Authors