Dr.SumのPython連携機能を使った機械学習

BI技術者の雑記

今回は、Dr.SumのPython連携機能を使って、KaggleのTitanicのチュートリアルを機械学習(ランダムフォレスト)で予測する方法をご説明します。

※Dr.SumのPython連携機能の説明がメインなので、ランダムフォレストやPythonの細かい説明は割愛します。

1. 手順① 環境構築

前提として、Dr.Sumサーバがインストールされている必要があります。(Ver.5.6以上)

①-1 データの準備

まず、Kaggleサイトから「タイタニック号の生存者データ」を入手します。
「training set (train.csv)」「test set (test.csv)」の両方をダウンロードしてください。

次に、入手したデータをDr.Sumのテーブルに登録します。

テーブルのデータをインメモリ化します。
「Dr.Sum 5.6 In-Memory Server」のサービスが起動しているか確認し、起動していない場合は起動します。

be26_01.png

作成したテーブルの上で右クリックし、「プロパティ」→「インメモリ化する」を選択します。
もう一度テーブルの上で右クリックし、「インメモリ」→「データをロード」を選択します。

be26_02.png

これでデータの準備は完了です。

①-2 Dr.Sumサーバの設定

<環境情報>
Dr.Sum Localhost:6001
Python連携ルート設定パス C:DrSum56Serversamplesudtf-py
クライアント用Python環境 C:DrSum56AdminToolsudtf-pythonpython
サーバ用Python環境 C:DrSum56IMServerlaunchpythonenvpython

「Dr.Sum 5.6 Launch Server」のサービスが起動しているか確認し、起動していない場合は起動します。

Dr.Sumのクライアントおよびサーバ用Python環境に、コマンドラインから使用するライブラリをインストールします。
例:C:DrSum56AdminToolsudtf-pythonpythonpython.exe -m pip install scikit-learn

2. 手順② 予測モデルの作成

Dr.Sumに登録したトレーニングデータを使用して、予測モデルを作成します。

②-1 予測モデル作成用スクリプトの作成

<ファイル名>
C:/DrSum56/Server/samples/udtf-py/script/titanic_train.py

<スクリプト>

import io		
import pandas as pd		
from sklearn.model_selection import train_test_split		
import joblib		
		
from sklearn.model_selection import train_test_split		
from sklearn.metrics import accuracy_score		
from sklearn.ensemble import RandomForestClassifier		
from sklearn.metrics import mean_squared_error		
		
import numpy as np		
import csv		
		
# Dr.SumからODBC接続で訓練データを取得		
def import_data():		
  import pyodbc		
  con = pyodbc.connect(DRIVER="Dr.Sum 5.6 ODBC Driver",		
            HOST="localhost", DATABASE="test", trusted_connection="yes",		
            user="Administrator", password="", port = "6001"		
            )		
  TBL = "titanic_train"		
  query = "SELECT * FROM {tbl} ;".format(tbl=TBL)		
  train_data = pd.read_sql(query, con)		
		
  return train_data		
		
		
def train(context,input):		
		
  input = preprocess(input)		
		
  # 訓練データとバリデーション用データを7:3で分割		
  train_x, test_x ,train_y, test_y = train_test_split(		
      input.drop("Survived", axis = 1).values, 		
      input["Survived"].values,  		
      test_size = 0.3, random_state = 0)		
		
		
  model = RandomForestClassifier(random_state=0)		
  model.fit(train_x, train_y)		
  y_pred = model.predict(test_x) # 予測		
  mse= mean_squared_error(test_y, y_pred) # 評価		
		
  # アウトプットとなるdataframeを定義		
  model_status = pd.DataFrame(columns = ["description", "value"])		
		
  # 各説明変数の重要度データをアウトプットとして追加する。		
  for i, feat in enumerate(input.columns[input.columns!="Survived"]):		
      model_status.loc[feat] = [feat, model.feature_importances_[i]]		
		
		
  # モデルの保存		
  stream = io.BytesIO()		
  joblib.dump(model, stream)		
  context.write_remote_file("PY_DATA_ROOT/titanic_model.sav", stream.getvalue())		
		
  return model_status		
		
def preprocess(df):		
  df['Fare'] = df['Fare'].fillna(df['Fare'].mean())		
  df['Age'] = df['Age'].fillna(df['Age'].mean())		
  df['Embarked'] = df['Embarked'].fillna('Unknown')		
  df['Sex'] = df['Sex'].apply(lambda x: 1 if x == 'male' else 0)		
  df['Embarked'] = df['Embarked'].map( {'S': 0, 'C': 1, 'Q': 2, 'Unknown': 3} ).astype(int)		
		
  df['Age'] = df['Age'].astype(int)		
  df['Fare'] = df['Fare'].astype(int)		
  df['Survived'] = df['Survived'].astype(int)		
  df['Pclass'] = df['Pclass'].astype(int)		
  df['SibSp'] = df['SibSp'].astype(int)		
  df['Parch'] = df['Parch'].astype(int)		
		
  df = df.drop(['Cabin','Name','PassengerId','Ticket'],axis=1)		
		
  return df		
		
def main():		
  import dspy.emulator		
  train_data = import_data()		
		
  # エミュレータを使ったデバッグ		
  builder=dspy.emulator.EmulatorBuilder(train_data)		
  emulator=builder.buildSerial(		
      py_file_path = "PY_SCRIPT_ROOT/titanic_train.py",		
      func_name = "train",		
      schema_func_name = "model_status",		
  )		
  result=emulator.execute(create_schema_mode = True) # Trueで結果表スキーマ取得関数を出力するようにする
  print(result)		
		
if __name__ == "__main__":		
  main()		

<スクリプトの概要>

関数 内容
def import_data() Dr.Sumからのデータ取得
def preprocess() データのクレンジング
def train() モデルの学習、作成
def main() メイン処理

②-2 実行

以下のコマンドでスクリプトを実行します。
C:DrSum56AdminToolsudtf-pythonpythonpython.exe C:DrSum56Serversamplesudtf-pyscripttitanic_train.py

モデルの内容が表示されます。

description value
0 Pclass 0.091828
1 Sex 0.285340
2 Age 0.298141
3 SibSp 0.059709
4 Parch 0.038032
5 Fare 0.185667
6 Embarked 0.041283

どうやら性別、年齢が生存に大きく影響していそうです。

モデルは同フォルダに作成されるので、作成されたファイルをC:DrSum56Serversamplesudtf-pydataにコピーしてください。
※今回のファイル名は「titanic_model.sav」です。

<補足>
実行すると下記のメッセージも表示されます。
この関数を同スクリプトに追加すると、コマンドラインで実施したことがDr.Sumサーバからも実施できますが、Dr.Sumサーバの呼び出しは「手順③ 予測の実行」で説明するため割愛します。

以下のスタブ関数をC:DrSum56Serversamplesudtf-pyscripttitanic_train.pyにコピーしてください。

def model_status(input_schema):
    return ['description VARCHAR', 'value NUMERIC']

3. 手順③ 予測の実行

「手順② 予測モデルの作成」で作成したモデルをDr.Sumサーバから呼び出し、テストデータの生存者判定を行います。
スクリプトはPythonで作成しますが、実行はDr.Sumサーバから呼び出します。

③-1 予測実行用スクリプトの作成

<ファイル名>
C:/DrSum56/Server/samples/udtf-py/script/titanic_train.py

<スクリプト>

import pandas as pd	
import joblib, io	
	
def predict_schema(input_schema):	
	
    return ['PassengerId NUMERIC', 'Survived NUMERIC']	
	
	
def predict(context, input):	
    test_data = preprocess(input)	
	
    load_stream = io.BytesIO(context.read_remote_file(f"PY_DATA_ROOT/titanic_model.sav"))	
    model = joblib.load(load_stream)	
    y_pred = model.predict(test_data.values) # 予測	
    output = test_data.assign(Survived = y_pred)	
	
    input = input['PassengerId']	
	
    output = output['Survived']	
	
    output = pd.concat([input, output],axis=1)	
	
    return output	
    	
def preprocess(df):	
  df['Fare'] = df['Fare'].fillna(df['Fare'].mean())	
  df['Age'] = df['Age'].fillna(df['Age'].mean())	
  df['Embarked'] = df['Embarked'].fillna('Unknown')	
  df['Sex'] = df['Sex'].apply(lambda x: 1 if x == 'male' else 0)	
  df['Embarked'] = df['Embarked'].map( {'S': 0, 'C': 1, 'Q': 2, 'Unknown': 3} ).astype(int)	
	
  df['Age'] = df['Age'].astype(int)	
  df['Fare'] = df['Fare'].astype(int)	
  df['Pclass'] = df['Pclass'].astype(int)	
  df['SibSp'] = df['SibSp'].astype(int)	
  df['Parch'] = df['Parch'].astype(int)	
	
  df = df.drop(['PassengerId','Cabin','Name','Ticket'],axis=1)	
	
  return df	

<スクリプトの概要>

関数 内容
def preprocess() データのクレンジング
def predict() モデルの読み込み、予測
def predict_schema() 結果のインターフェース

※Dr.Sumサーバから呼び出されるため、main処理はありません。

③-2 予測の実行(Dr.SumサーバのSQL ExecutorでSQL実行)

SELECT		
T.*		
FROM		
udtf::serial_py(		
    titanic_test,		
    py_file_path='PY_SCRIPT_ROOT/titanic_predict.py',		
    func_name='predict',		
    schema_func_name='predict_schema'		
) T		

実行すると予測結果が画面に表示されます。
※Survived=1は生存と予測

be26_03.png

4.おわりに

今回は、Dr.SumのPython連携機能を使って、Kaggleの「タイタニックの生存者予測」を実施する方法についてご紹介しました。

環境構築は多少手間がかかりますが、構築後の予測の実行は比較的簡単にできると思います。

BI_banner01.png