【Dr.Sum】重回帰モデルの作成と予測実行

# 目次
- はじめに
- 【おさらい】相関係数の算出結果
- 実装
- おわりに

# はじめに
※[前回の記事](https://qiita.com/s_komiyama/items/fd7374b757f99d609c8b)の続き
せっかくscikit-learnのサンプルデータソースを利用しているため、相関係数を算出した結果を元に重回帰モデルを作成していく。

# 【おさらい】相関係数の算出結果
scikit-learnに含まれているサンプルデータセットの「ボストンの住宅価格データ」を使用した相関係数の算出を行った。
MEDV_PRICE（住宅価格）に対する相関係数が大きいのはRM（平均部屋数）、LSTAT（給与の低い仕事に従事する人口の割合）だということが分かった。
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1571692/dcc96f55-9583-1cef-914e-83685b1476da.png)
今回は下記を前提として重回帰分析モデルを作成して予測してみる。

- 目的変数：MEDV_PRICE（住宅価格）
- 説明変数：RM（平均部屋数）、LSTAT（給与の低い仕事に従事する人口の割合）

# 実装
## 学習ロジックの追加
以下のメソッドを前回のコードへ追加

```python:Correlation.py
def get_learn(context, input):
    X = input.loc[:, ["RM", "LSTAT"]]  # RM列とLSTAT列のみを抽出
    y = input["MEDV_PRICE"]

    X = np.array(X).reshape(-1, 2)
    y = np.array(y).reshape(-1, 1)

    # 訓練データ：テストデータ＝7:3に分割
    from sklearn.model_selection import train_test_split
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.3, random_state=0)

    # モデルの学習
    from sklearn.linear_model import LinearRegression
    model = LinearRegression()
    model.fit(X_train, y_train)  # 訓練データで学習

    y_test_pred = model.predict(X_test)  # テストデータを用いて目的変数を予測
    rm = X_test[:, 0]  # テストデータ説明変数（X）のRM
    lstat = X_test[:, 1]  # テストデータ説明変数（X）のLSTAT
    predY = y_test_pred[:, 0]  # 予測結果目的変数（Y）のMEDV_PRICE
    pred = dict(testX_RM=rm, testX_LSTAT=lstat, testY_pred=predY)
    submission = pd.DataFrame(data=pred)

    return submission
```

## 「出力データスキーマのメソッド」出力
エミュレータでデバッグ実行して「出力データスキーマのメソッド」を出力する。
上述の学習。予測メソッドを追加の上エミュレータの実行メソッドを追加したメソッドへ変更しておく。
ここまでのソース全文は下記

```python:Correlation.py
import pandas as pd
import jaydebeapi
import os
import numpy as np


def get_learn(context, input):
    X = input.loc[:, ["RM", "LSTAT"]]  # RM列とLSTAT列のみを抽出
    y = input["MEDV_PRICE"]

    X = np.array(X).reshape(-1, 2)
    y = np.array(y).reshape(-1, 1)

    # 訓練データ：テストデータ＝7:3に分割
    from sklearn.model_selection import train_test_split
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.3, random_state=0)

    # モデルの学習
    from sklearn.linear_model import LinearRegression
    model = LinearRegression()
    model.fit(X_train, y_train)  # 訓練データで学習

    y_test_pred = model.predict(X_test)  # テストデータを用いて目的変数を予測
    rm = X_test[:, 0]  # テストデータ説明変数（X）のRM
    lstat = X_test[:, 1]  # テストデータ説明変数（X）のLSTAT
    predY = y_test_pred[:, 0]  # 予測結果目的変数（Y）のMEDV_PRICE
    pred = dict(testX_RM=rm, testX_LSTAT=lstat, testY_pred=predY)
    submission = pd.DataFrame(data=pred)

    return submission


def get_corr_schema(input_schema):
    # 出力データスキーマ
    return ['MEDV_PRICE NUMERIC', 'CRIM NUMERIC', 'ZN NUMERIC', 'INDUS NUMERIC', 'CHAS NUMERIC', 'NOX NUMERIC', 'RM NUMERIC', 'AGE NUMERIC', 'DIS NUMERIC', 'RAD NUMERIC', 'TAX NUMERIC', 'PTRATIO NUMERIC', 'B NUMERIC', 'LSTAT NUMERIC']


def get_corr(context, input):
    # 相関係数の算出
    corr = input.corr()
    return corr


if __name__ == "__main__":
    cwd = os.path.dirname(__file__)
    import dspy.emulator
    # Dr.SumのビューをJDBCで参照
    conn = jaydebeapi.connect("jp.co.dw_sapporo.JDBC.JDBCDriver",
                              "jdbc:dwods:localhost:6001:testDB",
                              ["User", "Pass"],
                              "C:\DrSum56\DevKit\java\jdbc\dwodsjd4.jar")
    curs = conn.cursor()
    sql = "select * from boston_view"
    sql_query = pd.read_sql_query(sql, conn)

    print("----- inputDr.Sum -----")
    # inputとなるデータのスキーマ解釈を出力
    dspy.emulator.show_ds_schema(sql_query)

    builder = dspy.emulator.EmulatorBuilder(
        sql_query,
        # エミュレータにおけるPY_SCRIPT_ROOT（省略時はカレントフォルダー）
        py_script_root=os.path.join(cwd, "../script"),
        # エミュレータにおけるPY_DATA_ROOT（省略時はカレントフォルダー）
        py_data_root=os.path.join(cwd, "../data")
    )
    emulator = builder.buildSerial(
        # 対象のPythonファイル名（当ファイル）
        py_file_path="PY_SCRIPT_ROOT/Correlation.py",
        # 対象の実行ロジックメソッド
        func_name="get_learn",
        # 出力データスキーマメソッド名
        schema_func_name="get_learn_schema",
    )
    curs.close()
    conn.close()
    # create_schema_mode=Trueで出力データスキーマメソッドを出力
    result = emulator.execute(create_schema_mode=True)
    print("----- OUTPUT -----")
    print(result)

```

エミュレータで実行

```
C:\DrSum56\Server\samples\udtf-py\script>C:\DrSum56\AdminTools\udtf-python\python\python.exe Correlation.py
```


出力結果

```
----- inputDr.Sum -----
{'MEDV_PRICE': 'NUMERIC', 'CRIM': 'NUMERIC', 'ZN': 'NUMERIC', 'INDUS': 'NUMERIC', 'CHAS': 'NUMERIC', 'NOX': 'NUMERIC', 'RM': 'NUMERIC', 'AGE': 'NUMERIC', 'DIS': 'NUMERIC', 'RAD': 'NUMERIC', 'TAX': 'NUMERIC', 'PTRATIO': 'NUMERIC', 'B': 'NUMERIC', 'LSTAT': 'NUMERIC'}


以下のスタブ関数をC:\DrSum56\Server\samples\udtf-py\script\../script\Correlation.pyにコピーしてください。

--------------------------------------------------------------------------------
def get_learn_schema(input_schema):
    return ['testX_RM NUMERIC', 'testX_LSTAT NUMERIC', 'testY_pred NUMERIC']
--------------------------------------------------------------------------------

----- OUTPUT -----
     testX_RM  testX_LSTAT  testY_pred
0       6.279        11.97   22.885443
1       5.872        15.37   18.804988
2       6.437        14.36   21.954645
3       6.122        14.10   20.756600
4       5.706        12.43   20.073717
..        ...          ...         ...
147     8.704         5.12   38.108770
148     6.546         5.33   28.551423
149     6.372        11.12   23.867382
150     7.249         4.81   31.970990
151     7.333         7.79   30.317395

[152 rows x 3 columns]
```

## 「出力データスキーマのメソッド」を追加
「以下のスタブ関数を～」で出力された「出力データスキーマのメソッド」を追加する。

```python:Correlation.py
import pandas as pd
import jaydebeapi
import os
import numpy as np


def get_learn_schema(input_schema):
    return ['testX_RM NUMERIC', 'testX_LSTAT NUMERIC', 'testY_pred NUMERIC']


def get_learn(context, input):
    X = input.loc[:, ["RM", "LSTAT"]]  # RM列とLSTAT列のみを抽出
    y = input["MEDV_PRICE"]

    X = np.array(X).reshape(-1, 2)
    y = np.array(y).reshape(-1, 1)

    # 訓練データ：テストデータ＝7:3に分割
    from sklearn.model_selection import train_test_split
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.3, random_state=0)

    # モデルの学習
    from sklearn.linear_model import LinearRegression
    model = LinearRegression()
    model.fit(X_train, y_train)  # 訓練データで学習

    y_test_pred = model.predict(X_test)  # テストデータを用いて目的変数を予測
    rm = X_test[:, 0]  # テストデータ説明変数（X）のRM
    lstat = X_test[:, 1]  # テストデータ説明変数（X）のLSTAT
    predY = y_test_pred[:, 0]  # 予測結果目的変数（Y）のMEDV_PRICE
    pred = dict(testX_RM=rm, testX_LSTAT=lstat, testY_pred=predY)
    submission = pd.DataFrame(data=pred)

    return submission


def get_corr_schema(input_schema):
    # 出力データスキーマ
    return ['MEDV_PRICE NUMERIC', 'CRIM NUMERIC', 'ZN NUMERIC', 'INDUS NUMERIC', 'CHAS NUMERIC', 'NOX NUMERIC', 'RM NUMERIC', 'AGE NUMERIC', 'DIS NUMERIC', 'RAD NUMERIC', 'TAX NUMERIC', 'PTRATIO NUMERIC', 'B NUMERIC', 'LSTAT NUMERIC']


def get_corr(context, input):
    # 相関係数の算出
    corr = input.corr()
    return corr


if __name__ == "__main__":
    cwd = os.path.dirname(__file__)
    import dspy.emulator
    # Dr.SumのビューをJDBCで参照
    conn = jaydebeapi.connect("jp.co.dw_sapporo.JDBC.JDBCDriver",
                              "jdbc:dwods:localhost:6001:testDB",
                              ["User", "Pass"],
                              "C:\DrSum56\DevKit\java\jdbc\dwodsjd4.jar")
    curs = conn.cursor()
    sql = "select * from boston_view"
    sql_query = pd.read_sql_query(sql, conn)

    print("----- inputDr.Sum -----")
    # inputとなるデータのスキーマ解釈を出力
    dspy.emulator.show_ds_schema(sql_query)

    builder = dspy.emulator.EmulatorBuilder(
        sql_query,
        # エミュレータにおけるPY_SCRIPT_ROOT（省略時はカレントフォルダー）
        py_script_root=os.path.join(cwd, "../script"),
        # エミュレータにおけるPY_DATA_ROOT（省略時はカレントフォルダー）
        py_data_root=os.path.join(cwd, "../data")
    )
    emulator = builder.buildSerial(
        # 対象のPythonファイル名（当ファイル）
        py_file_path="PY_SCRIPT_ROOT/Correlation.py",
        # 対象の実行ロジックメソッド
        func_name="get_learn",
        # 出力データスキーマメソッド名
        schema_func_name="get_learn_schema",
    )
    curs.close()
    conn.close()
    # create_schema_mode=Trueで出力データスキーマメソッドを出力
    result = emulator.execute(create_schema_mode=True)
    print("----- OUTPUT -----")
    print(result)
```

## 実環境で実行する
Dr.SumのSQL Executorで下記SQLを実行

```SQL
SELECT
*
FROM
udtf::serial_py( boston_view, py_file_path='PY_SCRIPT_ROOT/Correlation.py' , func_name='get_learn' , schema_func_name='get_learn_schema' ) T
```

出力結果
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1571692/2b7783d8-7a77-10ee-9938-a2c9658dac94.png)
テストデータのRM, LSTATに対して予測されたMEDV_PRICEが出力されていることがわかる。

# おわりに
今回は相関係数の出力結果を元に重回帰分析のモデル作成と予測を行った。
Dr.Sumとの連携という観点に主軸をおいているため学習モデルの評価等は実施していないが今後はそういった点も含めていきたい。

### 参考記事
- [【初心者でも簡単】Pythonのscikit-learnで重回帰分析](https://navaclass.com/python-multiple-regression/)
- [【Dr.Sum】インメモリビューのデータを利用した相関係数出力](https://qiita.com/s_komiyama/items/fd7374b757f99d609c8b)