データサイエンティストとシステムエンジニアがSnowflake活用にチャレンジした話
1.はじめに
NRIデジタルでは、組織の垣根を超え、異能を掛け合わせて、新しいことへのチャレンジを続けています。今回の記事では、その一例としてデータサイエンティストの菅とシステムエンジニアの荒井が新しいことにチャレンジした事例について紹介したいと思います。
具体的には、Snowflakeを活用した簡易な機械学習アプリ作成の取り組み例をご紹介します。
分析案件でお客さまの具体要件をヒアリングする際、デモストレーションは重要であり、データサイエンティストにも馴染みがあるPythonのみで簡易にwebアプリを作成できるStreamlitは、非常に有用だと考えております。
今回は、その技術の習熟や実践導入に向けた課題の洗い出しを目的として、アプリ作成に取り組みました。
2.データサイエンティストの取り組み
データサイエンティストは、sklearn提供のオープンデータであるカリフォルニア住宅価格のデータを用いて、Snowpark上で住宅価格を予測するモデルを作成しました。またStreamlitを用いて、「部屋数、緯度、経度」を選択し、選択地点と、その住宅の推定価格を返すアプリケーションを作成しました。
2.1 Snowparkを用いた機械学習モデル構築
SnowparkはSnowflakeのエコシステムにおいてデータ処理を向上させるための拡張機能であり、Snowflake上で大規模なデータセットを処理し、クエリを高速に実行できます。
まずはワークシートから、Snowpark経由でSnowflake上のデータを読み込みます。その後、to_pandasにより、データサイエンティストが扱い慣れたdataframe形式に変換し、前処理・機械学習モデルを作成します。なお、データが大きすぎる場合は、一気にデータをメモリに載せないto_pandas_batchesでの変換が有効です。
続いて、「学習データ数:テストデータ数=8:2」に分割し、機械学習モデルは、LightGBMを採用しました。8割の学習データに対してはK分割交差検証を実施し、最良の学習モデルを選定しました。学習済モデルは、事前に作成した@dash_modelsステージに配置します。
# ステージにトレーニング済モデルをアップロード
model_output_dir = '/tmp'
model_file = os.path.join(model_output_dir, 'model.joblib')
dump(best_model, model_file)
session.file.put(model_file,"@dash_models",overwrite=True)
続いて、学習済モデルをUDFに登録します。
@udf(name='predict_price',session=session,replace=True,is_permanent=True,stage_location='@dash_models')
def predict_price(house_specs: list) -> float:
import sys
import pandas as pd
from joblib import load
IMPORT_DIRECTORY_NAME = "snowflake_import_directory"
import_dir = sys._xoptions[IMPORT_DIRECTORY_NAME]
model_file = import_dir + 'model.joblib.gz'
model = load(model_file)
df = pd.DataFrame([house_specs], columns=['LATITUDE','LONGITUDE','AVEROOMS'])
PRED_PRICE = abs(model.predict(df)[0])
return PRED_PRICE
2.2 Streamlitを用いた地図の住宅価格予測
Streamlitは、データ可視化や分析アプリケーションの迅速な構築を可能にするPythonベースのフレームワークです。これにより、直感的な方法でデータを探索し、結果を共有できます。
このStreamlitを用いて、「部屋数、緯度、経度」を選択し、選択地点と、その住宅の推定価格を返すアプリケーションを作成します。
2.1章で作成したUDF関数のpredict_priceは、Streamlit上では下記関数内で呼び出します。
# Get the current credentials
session = get_active_session()
@st.cache_data(show_spinner=False)
def predict(query_dict):
df_predicted_roi = session.sql(f"SELECT predict_price(array_construct(\
{query_dict['LATITUDE']},\
{query_dict['LONGITUDE']},\
{query_dict['AVEROOMS']})) as PRED_PRICE").to_pandas()
pred_price = df_predicted_roi["PRED_PRICE"].values[0]
return pred_price
続いて地図可視化については、定番であるfoliumを使って可視化を試みましたが、in Snowflakeでは、セキュリティポリシーに違反するため、利用できませんでした。
そこで今回は、Streamlit in Snowflakeでも利用可能なst.mapを使って選択した緯度、経度の地点を表示させました。また「部屋数、緯度、経度」はスライドバーで選択し、住宅の推定価格を返すアプリケーションを作成しました。
また、Streamlit in Snowflakeでは、アプリ実行中は課金が発生しますが、下記の通り15分以上放置すると自動停止するようにデフォルトで設定されているので、高額課金を予防してくれて安心です。
3.システムエンジニアの取り組み
データサイエンティストが実行するクエリを受けるプラットフォーム側でも、システムエンジニアが中心となって新技術へのチャレンジを進めています。現在は、Snowflakeのプレビュー機能(2/15時点)であるIcebergテーブルに注目しており、前述のアプリケーションでもデータベースレイヤはIcebergテーブルで実装しています。
Icebergテーブルは、オープンソースの大規模分析向けテーブル形式であるApache IcebergをSnowflake上で利用できるようにしたもので、下記のような特徴的な機能があります。
・ACID (atomicity, consistency, isolation, durability) transactions
・Schema evolution
・Hidden partitioning
・Table snapshots
Icebergテーブルに着目した経緯をご説明します。
そもそも、データ分析という活動は、事前に要件を定義することが困難で、試行錯誤のサイクルの中で方針が見えてくるという性質があると考えています。
当然ではありますが、分析内容が変われば、必要なデータや最適なテーブル構造は変化していきます。何も工夫が無ければ、その都度エンジニアがデータベースのチューニング等の対応をする流れになりますが、ここで発生するコミュケーションのロスや待ち時間が、データ分析を進める上では足かせになります。
このような状況が見え隠れする中で、プレビューではありますが、SnowflakeでIcebergテーブルを利用できるようになりました。IcebergテーブルのSchema evolutionやHidden partitioningなど、データ分析者が、データベースの構造を強く意識しなくても良いような機能が、分析効率の向上に有効に働くのではないかと考え、その将来性含めて注目して使い始めた、というのが、今回の経緯となります。
もちろん、マイナスに働く可能性もあるので、その辺りの見極め、検証を注意深くしていこうと動き出した段階になります。プレビュー段階であるため、全ての機能が使えるわけではないですが、デモンストレーションや社内向けツールなどで利用できる場面では、積極的に利用を進めています。
4.おわりに
このようにNRIデジタルでは、組織の垣根を超え、異能を掛け合わせて、新しいことにチャレンジを続けています。今回はほんの一例に過ぎませんが、このような取り組みが社内のいたるところで行われています。既存の枠組みにとらわれず、新しいことにどんどんチャレンジしたい方、ぜひジョインして一緒にまだ見ぬ世界を切り拓きましょう。