[Oracle Cloud] Autonomous Database+OMLノートブックで機械学習してみた(PL/SQL編)

# はじめに
Autonomous Databaseには、Oracle Machine Learningユーザー・インタフェースが用意されており、OML Notebooks、OML AutoML UI、OML Models、テンプレート・サンプル・ノートブックなどのOracle Machine Learningのコンポーネントおよび機能にすばやくアクセスできます。
OML Notebooks(ノートブック)を使用してPL/SQLを使った機械学習をしてみました。

### OML ノートブック
モデル開発用の共同共有ワークスペースとして提供され、Autonomous Database内のすべてのデータへの直接接続します。
データおよび機械学習の結果を表示するビジュアル・パレットがあり、ディスカッション、ドキュメント、実行および結果が一緒に表示される共有プラットフォームです。

利用するには、Autonomous DatabaseのユーザでOMLを有効化します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108635/74b85ae8-fbb3-d986-7a01-35963bb9c301.png)


# サンプルシナリオ
SQL Developer に含まれるチュートリアル用データを使います。
以下のスクリプトを作ってサンプルデータを作成します。

```
alter session set nls_date_language = 'AMERICAN';
@C:\sqldeveloper\dataminer\scripts\instInsurCustData.sql {username}
```

INSUR_CUST_LTV_SAMPLE表は、保険商品を購入したかしなかったか結果が入った顧客情報表です。
BUY_INSURANCE列を教師データとして、分類モデル３つのアルゴリズムで作成し、モデルを比較します。
精度のよいモデルを使って予測を実施します。

# OMLノートブックをはじめる
## データベース・アクションでOML UIの起動
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108635/5c4a2329-85c8-6e97-bda8-a734612e95a9.png)
OMLを有効化したユーザでログイン
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108635/8a5b6750-16c4-0555-e2f6-c0abd6910866.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108635/faaf943c-8e9f-39f1-6b15-1faf020144af.png)

左上のハンバーガーメニューから「プロジェクト」＞「ノートブック」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108635/93dda110-771b-9b23-0a7f-9ef711531736.png)

## ノートブックの作成
[作成」をクリックし、名前を入力しノートブックを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108635/a36a3d16-ef31-f301-121d-ab5ed4baa90f.png)

作成したノートブックを選択しノートブックを起動します。

# データの確認
### 教師データの確認

```
%sql
SELECT * FROM INSUR_CUST_LTV_SAMPLE WHERE ROWNUM < 50;
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108635/edef0e96-354f-9682-ae3b-5da80e16fd0b.png)

### ターゲット列の値のサマリ

```
%sql

SELECT BUY_INSURANCE, COUNT(*)
FROM INSUR_CUST_LTV_SAMPLE
GROUP BY BUY_INSURANCE
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108635/074f797b-ba79-5b99-8456-e926685130fc.png)

ボタンをクリックしグラフ表示が可能
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108635/3a7f3e33-2510-9bd6-2f3b-76bff9f4af41.png)

### 顧客情報 (MARITAL_STATUS列)  

```
SELECT MARITAL_STATUS, COUNT(*) 
FROM INSUR_CUST_LTV_SAMPLE
GROUP BY MARITAL_STATUS;
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108635/1b4e3013-27cd-03af-6e90-32e7a96a471d.png)

### BUY_INSURANCEの値に影響がある列の調査

```
%script 
BEGIN DBMS_DATA_MINING.DROP_MODEL('ai_explain_output_buy_insur_bin');
EXCEPTION WHEN OTHERS THEN NULL; END;

DECLARE
    v_setlst DBMS_DATA_MINING.SETTING_LIST;
BEGIN
    v_setlst('ALGO_NAME')        := 'ALGO_AI_MDL';
    V_setlst('PREP_AUTO')        := 'ON';

    DBMS_DATA_MINING.CREATE_MODEL2(
        MODEL_NAME        => 'ai_explain_output_buy_insur_bin',
        MINING_FUNCTION   => 'ATTRIBUTE_IMPORTANCE',
        DATA_QUERY        => 'select * from INSUR_CUST_LTV_SAMPLE',
        SET_LIST          => v_setlst,
        CASE_ID_COLUMN_NAME => 'CUSTOMER_ID',
        TARGET_COLUMN_NAME  => 'BUY_INSURANCE');
END;
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108635/49bac183-717d-70dc-606a-6a0e9b5c0bee.png)

### BUY_INSURANCEの値に影響がある列の上位15を表示

```
%sql

SELECT * FROM DM$VAai_explain_output_buy_insur_bin WHERE ROWNUM <16;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108635/23b589d6-9ee4-b976-0930-4d5b774c3bfa.png)


### DBMS_DATA_MINING_TRANSFORMS パッケージを使ったヒストグラムの作成

```
%script

-- Create a view that bins ALL the numeric columns.  

BEGIN

BEGIN 
EXECUTE IMMEDIATE 'DROP TABLE bin_num_tbl';
EXCEPTION WHEN OTHERS THEN NULL; 
END; 

BEGIN
EXECUTE IMMEDIATE 'DROP VIEW mining_data_bin_view';
EXCEPTION WHEN OTHERS THEN NULL; 
END; 


   dbms_data_mining_transform.create_bin_num(
           bin_table_name     => 'bin_num_tbl');

   dbms_data_mining_transform.insert_autobin_num_eqwidth(
           bin_table_name     => 'bin_num_tbl',
           data_table_name    => 'INSUR_CUST_LTV_SAMPLE',
           bin_num            => 5,
           max_bin_num        => 10,
           exclude_list       => dbms_data_mining_transform.COLUMN_LIST('CUSTOMER_ID'));

  dbms_data_mining_transform.xform_bin_num(
           bin_table_name      => 'bin_num_tbl',
           data_table_name     => 'INSUR_CUST_LTV_SAMPLE',
           xform_view_name     => 'mining_data_bin_view');
END;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108635/49bac183-717d-70dc-606a-6a0e9b5c0bee.png)


### ヒストグラムの表示 例：BANK_FUNDS

```
%sql

SELECT CUSTOMER_ID, AGE, SALARY, BANK_FUNDS, CREDIT_CARD_LIMITS, MORTGAGE_AMOUNT, LTV FROM MINING_DATA_BIN_VIEW;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108635/c0d7e3ca-589a-5490-5245-98f8c621a63a.png)


# モデルの作成
ディシジョンツリー(DT)、サポートベクターマシン(SVM)、ランダムフォレストのアルゴリズムを使ったモデルを作成します。

### ディシジョンツリー(DT)モデルの作成

```
%script

BEGIN
  DBMS_DATA_MINING.DROP_MODEL('N2_CLASS_MODEL_DT');
  EXCEPTION WHEN OTHERS THEN NULL; 
END;
/
DECLARE
    v_setlst DBMS_DATA_MINING.SETTING_LIST;
BEGIN
    v_setlst('PREP_AUTO') := 'ON';
    v_setlst('ALGO_NAME') := 'ALGO_DECISION_TREE';
    DBMS_DATA_MINING.CREATE_MODEL2(
	MODEL_NAME        => 'N2_CLASS_MODEL_DT',
        MINING_FUNCTION   => 'CLASSIFICATION',
        DATA_QUERY        => 'SELECT * FROM INSUR_CUST_LTV_SAMPLE',
        SET_LIST          => v_setlst,
        CASE_ID_COLUMN_NAME => 'CUSTOMER_ID',
        TARGET_COLUMN_NAME  => 'BUY_INSURANCE');
END;
```

### ディシジョンツリー(DT)モデルの評価値の計算

```
%script

-- Drop result tables
BEGIN
  EXECUTE IMMEDIATE 'DROP TABLE N2_APPLY_RESULT_DT PURGE';
  EXCEPTION WHEN OTHERS THEN NULL; 
END;
/
BEGIN
  EXECUTE IMMEDIATE 'DROP TABLE N2_LIFT_TABLE_DT PURGE';
EXCEPTION WHEN OTHERS THEN NULL; 
END;
/    
-- Score the data and compute lift
BEGIN
DBMS_DATA_MINING.APPLY('N2_CLASS_MODEL_DT','INSUR_CUST_LTV_APPLY','CUSTOMER_ID','N2_APPLY_RESULT_DT');
DBMS_DATA_MINING.COMPUTE_LIFT('N2_APPLY_RESULT_DT','INSUR_CUST_LTV_SAMPLE','CUSTOMER_ID','BUY_INSURANCE','N2_LIFT_TABLE_DT','Yes','PREDICTION','PROBABILITY',100);
END;
```

### サポートベクターマシン(SVM)モデルの作成

```
%script

BEGIN
DBMS_DATA_MINING.DROP_MODEL('N2_CLASS_MODEL_SVM');
EXCEPTION WHEN OTHERS THEN NULL; 
END;
/

DECLARE
    v_setlst DBMS_DATA_MINING.SETTING_LIST;
BEGIN
    v_setlst('PREP_AUTO') := 'ON';
    v_setlst('ALGO_NAME') := 'ALGO_SUPPORT_VECTOR_MACHINES';
    v_setlst('SVMS_KERNEL_FUNCTION') := 'SVMS_GAUSSIAN';
    DBMS_DATA_MINING.CREATE_MODEL2(
	MODEL_NAME        => 'N2_CLASS_MODEL_SVM',
        MINING_FUNCTION   => 'CLASSIFICATION',
        DATA_QUERY        => 'SELECT * FROM INSUR_CUST_LTV_SAMPLE',
        SET_LIST          => v_setlst,
        CASE_ID_COLUMN_NAME => 'CUSTOMER_ID',
        TARGET_COLUMN_NAME  => 'BUY_INSURANCE');
END;
```

### サポートベクターマシン(SVM)モデルの評価値の計算

```
%script

-- Drop result tables
BEGIN
  EXECUTE IMMEDIATE 'DROP TABLE N2_APPLY_RESULT_SVM PURGE';
  EXCEPTION WHEN OTHERS THEN NULL; 
END;
/
BEGIN
  EXECUTE IMMEDIATE 'DROP TABLE N2_LIFT_TABLE_SVM PURGE';
EXCEPTION WHEN OTHERS THEN NULL; 
END;
/
-- Score the data and compute lift
BEGIN
DBMS_DATA_MINING.APPLY('N2_CLASS_MODEL_SVM','INSUR_CUST_LTV_APPLY','CUSTOMER_ID','N2_APPLY_RESULT_SVM');
DBMS_DATA_MINING.COMPUTE_LIFT('N2_APPLY_RESULT_SVM','INSUR_CUST_LTV_SAMPLE','CUSTOMER_ID','BUY_INSURANCE','N2_LIFT_TABLE_SVM','Yes','PREDICTION','PROBABILITY',100);
END;
```

### ランダムフォレスト(RM)モデルの作成

```
%script
BEGIN
DBMS_DATA_MINING.DROP_MODEL('N2_CLASS_MODEL_RF');
EXCEPTION WHEN OTHERS THEN NULL; 
END;
/

DECLARE
    v_setlst DBMS_DATA_MINING.SETTING_LIST;
BEGIN
    v_setlst('PREP_AUTO') := 'ON';
    v_setlst('ALGO_NAME') := 'ALGO_RANDOM_FOREST';
    DBMS_DATA_MINING.CREATE_MODEL2(
	MODEL_NAME        => 'N2_CLASS_MODEL_RF',
        MINING_FUNCTION   => 'CLASSIFICATION',
        DATA_QUERY        => 'SELECT * FROM INSUR_CUST_LTV_SAMPLE',
        SET_LIST          => v_setlst,
        CASE_ID_COLUMN_NAME => 'CUSTOMER_ID',
        TARGET_COLUMN_NAME  => 'BUY_INSURANCE');
END;
/
```

### ランダムフォレスト(RM)モデルの評価値の計算

```
%script

-- Drop result tables
BEGIN
  EXECUTE IMMEDIATE 'DROP TABLE N2_APPLY_RESULT_RF PURGE';
  EXCEPTION WHEN OTHERS THEN NULL; 
END;
/
BEGIN
  EXECUTE IMMEDIATE 'DROP TABLE N2_LIFT_TABLE_RF PURGE';
EXCEPTION WHEN OTHERS THEN NULL; 
END;
/

-- Score the data and compute lift
BEGIN
DBMS_DATA_MINING.APPLY('N2_CLASS_MODEL_RF','INSUR_CUST_LTV_APPLY','CUSTOMER_ID','N2_APPLY_RESULT_RF');
DBMS_DATA_MINING.COMPUTE_LIFT('N2_APPLY_RESULT_RF','INSUR_CUST_LTV_SAMPLE','CUSTOMER_ID','BUY_INSURANCE','N2_LIFT_TABLE_RF','Yes','PREDICTION','PROBABILITY',100);
END;
/
```

# モデルの比較

### 比較用ビューの作成

```
%script

CREATE OR REPLACE VIEW ALL_LIST_DATA_V AS
SELECT QUANTILE_NUMBER, GAIN_CUMULATIVE, CAST('DECISION_TREE' AS VARCHAR(50)) AS ALGO_NAME 
  FROM N2_LIFT_TABLE_DT
UNION
SELECT QUANTILE_NUMBER, GAIN_CUMULATIVE, CAST('SVM' AS VARCHAR(50)) AS ALGO_NAME 
  FROM N2_LIFT_TABLE_SVM
UNION 
SELECT QUANTILE_NUMBER, GAIN_CUMULATIVE, CAST('RANDOM_FOREST' AS VARCHAR(50)) AS ALGO_NAME 
  FROM N2_LIFT_TABLE_RF;
```

### モデルの比較

```
%sql

SELECT A.ALGO_NAME, A.QUANTILE_NUMBER, ROUND(A.GAIN_CUMULATIVE*100,2) GAIN_CUMULATIVE, B.RANDOM_GUESS
FROM ALL_LIST_DATA_V A,
     (SELECT ALGO_NAME, QUANTILE_NUMBER, QUANTILE_NUMBER RANDOM_GUESS FROM ALL_LIST_DATA_V) B
WHERE A.QUANTILE_NUMBER = B.QUANTILE_NUMBER AND A.ALGO_NAME = B.ALGO_NAME;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108635/3ce3dd28-59b2-4e69-2dec-fe3ee897e248.png)

今回の結果では、ランダムフォレストがよりよいモデルとなりました。

# 予測
新しい顧客にモデルを適用して、BUY_INSURANCEが「はい」になる可能性が高い顧客を予測
新しい顧客データがINSUR_CUST_LTV_APPLY表として用意

```
%sql 

SELECT CUSTOMER_ID, BUY_INSURANCE, PREDICTION(N2_CLASS_MODEL_RF USING *) PREDICTION, ROUND(PREDICTION_PROBABILITY(N2_CLASS_MODEL_RF, NULL USING *)*100,2) PROB_BUY_INSURANCE 
FROM   INSUR_CUST_LTV_APPLY 
ORDER BY PROB_BUY_INSURANCE DESC
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108635/30dfa157-07ec-bdf3-6fdd-53a087d35f1a.png)

データ可視化ツールで利用しやすいように、モデルの予測と確率で新しい表を作成します。

```
%script

BEGIN
  EXECUTE IMMEDIATE 'DROP TABLE BUY_INSUR_NEW_PREDICTIONS PURGE';
  EXCEPTION WHEN OTHERS THEN NULL; 
END;
/

CREATE TABLE BUY_INSUR_NEW_PREDICTIONS AS 
SELECT A.CUSTOMER_ID
	, A.PREDICTION
	, A.PROB_BUY_INSUR
	, B.STATE, B.AGE, B.SALARY, B.BANK_FUNDS, B.CREDIT_CARD_LIMITS, B.MORTGAGE_AMOUNT, B.LTV, B.MARITAL_STATUS
FROM (SELECT CUSTOMER_ID, PREDICTION(N2_CLASS_MODEL_RF USING *) PREDICTION, round(PREDICTION_PROBABILITY(N2_CLASS_MODEL_RF, 'Yes' USING *),2) PROB_BUY_INSUR FROM INSUR_CUST_LTV_APPLY) A
    , INSUR_CUST_LTV_APPLY B
WHERE A.CUSTOMER_ID = B.CUSTOMER_ID;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108635/349ae415-58a4-be1a-38cb-3e7270095761.png)

作成したBUY_INSUR_NEW_PREDICTIONS表から「Yes」の顧客をPROB_BUY_INSURでソートして確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108635/10b8b63f-4aef-7612-1ba0-05cc5b5e992d.png)


# おわりに

OMLノートブックを使って結果をグラフ化しながら機械学習モデル作成、評価ができました。

# 参考情報

- [CREATE_MODELプロシージャ](https://docs.oracle.com/cd/F19136_01/arpls/DBMS_DATA_MINING.html#GUID-7F525A4E-9C93-44D6-BFFF-10BC018CD4A6)
- [Machine Learning on ADB – Choose your Journey](https://apexapps.oracle.com/pls/apex/r/dbpm/livelabs/view-workshop?wid=861&clear=RR,180)