SAS Viyaによる基本的な予測モデリングデモを体験する流れ

SAS ViyaはAIプラットフォームを提供しています。デモもあるのですが、全体が英語なので利用するまでに躊躇してしまう人も多いかと思います。そこで、Pythonで基本的な予測モデリングデモを体験するまでの流れを紹介します。

# 利用開始まで

まず SASの開発者サイトにアクセスします。開発者サイトは [https://developer.sas.com/home.html](https://developer.sas.com/home.html) です。

![Screenshot_ 2018-06-27 14.59.58.png](https://qiita-image-store.s3.amazonaws.com/0/197026/8acfe222-35ea-79bc-d098-77e42347902e.png)

そして、 [Get started with your SAS Viya Developer Trial](https://www.sas.com/en_us/trials/software/viya-developer/form.html) を押します。

![Screenshot_ 2018-06-27 15.00.52.png](https://qiita-image-store.s3.amazonaws.com/0/197026/5a595a61-9133-90bc-9dfa-6ac5569e6909.png)


試すためには SAS Profile （SASプロファイル） というのが必要です。まず [Create one](https://login.sas.com/opensso/UI/Login?realm=/extweb&goto=https://www.sas.com/en_us/trials/software/viya-developer/form.html) をクリックします。

<img width="2970" alt="Screenshot_ 2018-06-27 15.04.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/197026/1ee63a5b-a81e-0e22-17c8-90deb0c58019.png">

SASプロファイルを登録するをクリックします。

![Screenshot_ 2018-06-27 15.05.26.png](https://qiita-image-store.s3.amazonaws.com/0/197026/ef1c48e1-5274-85b4-83b4-50519b28408f.png)


情報を入力します。

![Screenshot_ 2018-06-27 15.05.36.png](https://qiita-image-store.s3.amazonaws.com/0/197026/b6167273-8309-eac3-6cb8-f3d9d88ecb9f.png)



フォームを送信するとメールが送られてきます。

![Screenshot_ 2018-06-27 15.06.23.png](https://qiita-image-store.s3.amazonaws.com/0/197026/89461c01-9991-1861-a09c-4bdb6b2fd8ae.png)


メールに書かれている **SASプロファイルをアクティベートする** をクリックします。

![Screenshot_ 2018-06-27 15.08.01.png](https://qiita-image-store.s3.amazonaws.com/0/197026/bb5ed70b-931a-f4c2-4d56-b04094bba800.png)


そしてパスワードを設定します。

![Screenshot_ 2018-06-27 15.08.34.png](https://qiita-image-store.s3.amazonaws.com/0/197026/5e631d6b-92df-949c-683d-f23ecbbea39b.png)


SASプロファイルがアクティベートされます。 **続ける** をクリックします。

![Screenshot_ 2018-06-27 15.09.03.png](https://qiita-image-store.s3.amazonaws.com/0/197026/8acd3639-0522-d3ba-7570-08fe31d3bf4c.png)


そうすると先ほどの SAS® Viya® Developer Trial の画面に戻ってきますので、 今度はSign In をクリックします。

![Screenshot_ 2018-06-27 15.09.43.png](https://qiita-image-store.s3.amazonaws.com/0/197026/d70b2da0-634a-3e99-2200-7de7b76b2001.png)

先ほど登録したSASプロファイルのID、パスワードでログインします。

![Screenshot_ 2018-06-27 15.10.15.png](https://qiita-image-store.s3.amazonaws.com/0/197026/064c9340-36fd-792f-9eb8-14da0d58c5dc.png)


ログインすると SAS® Viya® Developer Trial の画面に戻ってきますが、今回はプロファイルの内容が入力されているはずです。一番下にある Sign me upボタンをクリックします。

![Screenshot_ 2018-06-27 15.11.20.png](https://qiita-image-store.s3.amazonaws.com/0/197026/40903d65-8cd9-a359-5be4-881317f32db4.png)


これで SAS® Viya® Developer Trial の申し込みが終わりました。数分後にメールが送られてきます。

![Screenshot_ 2018-06-27 15.12.24.png](https://qiita-image-store.s3.amazonaws.com/0/197026/c0ac5de5-2f22-1c9a-a37c-ce7fed3363f1.png)


送られてきたメールにある **Log in to your Trial Portal** のリンクをクリックします。

<img width="1824" alt="Screenshot_ 2018-06-27 15.13.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/197026/186feb88-d04a-5fc4-2a3a-d5feb89ab0a3.png">


利用規約が表示されますので、問題なければAcceptボタンを押します。

![Screenshot_ 2018-06-27 15.14.21.png](https://qiita-image-store.s3.amazonaws.com/0/197026/777cb262-975b-05f6-fd17-94f799d120fb.png)


そうするとログインフォームが出るので、先ほど登録したID、パスワードでログインします。

![Screenshot_ 2018-06-27 15.14.55.png](https://qiita-image-store.s3.amazonaws.com/0/197026/a855abd5-63f7-b96d-3f1f-4e499fb17713.png)


ログインすると Getting Started: SAS® Viya™ Developer Trial が表示されます。

![Screenshot_ 2018-06-27 15.15.39.png](https://qiita-image-store.s3.amazonaws.com/0/197026/b06118e0-bcfb-1864-58c9-5ac897d57c97.png)



下の方にある Get started with Python, R, and SAS API via Jupyter Notebook をクリックします。

![Screenshot_ 2018-06-27 15.16.30.png](https://qiita-image-store.s3.amazonaws.com/0/197026/7b9c13ac-18fc-0825-2663-a390c06564ab.png)


さらに Start My Trial Now をクリックします。

<img width="2436" alt="Screenshot_ 2018-06-27 15.16.35.png" src="https://qiita-image-store.s3.amazonaws.com/0/197026/5fe09c63-be6c-880b-c380-2ae0c25c9d24.png">


そうすると見慣れたJupyter Notebookの画面が出ます。Pythonフォルダの中にある Basic Predictive Modeling Example.ipynb をクリックします。

![Screenshot_ 2018-06-27 15.16.57.png](https://qiita-image-store.s3.amazonaws.com/0/197026/48c4b49c-e513-73c8-c19d-6b9c559a9b34.png)


----

ここからは Basic Predictive Modeling Example.ipynb に書かれている内容の意訳です。英語の後に日本語を参考として載せています。

# Overview（概要）

This is a simple end to end example of how you can use SAS Viya for analysis

これは分析のためにSAS Viyaを使用する方法の簡単な例です。

The example follows these steps:

この例は以下の手順に沿って行います。

1. Importing the needed Python packages（必要なPythonパッケージをインポートする）
1. Starting a CAS session on an already running CAS server（実行中のCASサーバでCASセッションを開始する）
1. Checking the server status（サーバの状態を確認する）
1. Loading data from the local file system to the CAS server（ローカルファイルからCASサーバへのデータの読み込み）
1. Explore the data（データを調べる）
1. Impute missing values（欠損値の代入）
1. Partition the data into training and validation partitions（データをパーティション（トレーニングパーティションと検証）に分割する）
1. Build a decision tree（ディシジョンツリーを構築する）
1. Build a neural network（ニューラルネットワークを構築する）
1. Build a decision forest（ディシジョンフォレストを構築する）
1. Build a gradient boost（Gradient Boostingを作成する）
1. Assess the models（モデルを評価する）
1. Build ROC charts（ROCチャートを作成する）

## Setup and initialize（セットアップと初期化）

Find doc for all the CAS actions [here](http://casjml01.unx.sas.com:8080/job/Actions_ref_doc_vb005/ws/casaref/index.html) 

CASアクションのドキュメントについては[このドキュメント](http://casjml01.unx.sas.com:8080/job/Actions_ref_doc_vb005/ws/casaref/index.html)を見てください。
両方でターゲット変数の
In this code we import the needed packages and we assign variables for the modeling details that will be used later in the analysis

このコードでは、必要なパッケージをインポートし、解析の後半で使用されるモデリング用の変数を割り当てます。

```python
from swat import *
from swat.render import render_html
from pprint import pprint
from matplotlib import pyplot as plt
import pandas as pd
import sys
%matplotlib inline

target          = "bad"
class_inputs    = ["reason", "job"]
class_vars      = [target] + class_inputs
interval_inputs = ["im_clage", "clno", "im_debtinc", "loan", "mortdue", "value", "im_yoj", "im_ninq", "derog", "im_delinq"]
all_inputs      = interval_inputs + class_inputs

indata_dir = '../data'
indata = 'hmeq'
```

## Start CAS session（CASセッションの開始）

In this code we assign values for the cashost, casport, and casauth values. These are then used to establish a CAS session named `sess`.

このコードでは cashost、casportおよびcasauthに値を割り当てます。 これらは、 `sess` という名前のCASセッションを確立するために使用します。

```python
cashost='localhost'
casport=5570
casauth='~/.authinfo'
sess = CAS(cashost, casport, authinfo=casauth, caslib="casuser")

# Load the needed action sets for this example:
# このデモで必要なアクションセットをロードします：
sess.loadactionset(actionset="dataStep")
sess.loadactionset(actionset="dataPreprocess")
sess.loadactionset(actionset="cardinality")
sess.loadactionset(actionset="sampling")
sess.loadactionset(actionset="regression")
sess.loadactionset(actionset="decisionTree")
sess.loadactionset(actionset="neuralNet")
sess.loadactionset(actionset="svm")
sess.loadactionset(actionset="astore")
sess.loadactionset(actionset="percentile")
```

## Load data into CAS（CASにデータを読み込む）

```python
if not sess.table.tableExists(table=indata).exists:
    indata = sess.upload_file(indata_dir+"/"+indata+".csv", casout={"name":indata})
```

## Explore and Impute missing values（データの探索および欠損値の代入）

```python
sess.summary(indata)
```

#### Explore data and plot missing values（データの探索および欠損値の確認）

```python
sess.cardinality.summarize(
  table=indata, 
  cardinality={"name":"data_card", "replace":True}
)

tbl_data_card=sess.CASTable('data_card')
tbl_data_card.where='_NMISS_>0'
print("Data Summary".center(80, '-')) # print title
tbl_data_card.fetch() # print obs

tbl_data_card.vars=['_VARNAME_', '_NMISS_', '_NOBS_']
allRows=20000  # Assuming max rows in data_card table is <= 20,000
df_data_card=tbl_data_card.fetch(to=allRows)['Fetch']
df_data_card['PERCENT_MISSING']=(df_data_card['_NMISS_']/df_data_card['_NOBS_'])*100

tbl_forplot=pd.Series(list(df_data_card['PERCENT_MISSING']), index=list(df_data_card['_VARNAME_']))
ax=tbl_forplot.plot(
  kind='bar', 
  title='Percentage of Missing Values'
)
ax.set_ylabel('Percent Missing')
ax.set_xlabel('Variable Names');
```

#### Impute missing values（欠損値の代入）

```python
r=sess.dataPreprocess.transform(
  table=indata,
  casOut={"name":"hmeq_prepped", "replace":True},
  copyAllVars=True,
  outVarsNameGlobalPrefix="IM",
  requestPackages=[
    {"impute":{"method":"MEAN"}, "inputs":{"clage"}},
    {"impute":{"method":"MEDIAN"}, "inputs":{"delinq"}},
    {"impute":{"method":"VALUE", "valuesContinuous":{2}}, "inputs":{"ninq"}},
    {"impute":{"method":"VALUE", "valuesContinuous":{35.0, 7, 2}}, "inputs":{"debtinc", "yoj"}}
  ]
)
render_html(r)
```

## Partition data into Training and Validation（トレーニングと検証用パーティションにデータを投入）

The stratified action in the sampling actionset allows us to create two partition and observe the reponse rate of the target variable `bad` in both training and validation

サンプルデータのアクションセットにある階層化されたアクションで2つのパーティションを作成します。トレーニングと検証の両方でターゲット変数 `bad` の応答率を観察できるようにします。

```python
sess.sampling.stratified(
  table={"name":"hmeq_prepped", "groupBy":target},
  output={"casOut":{"name":"hmeq_part", "replace":True}, "copyVars":"ALL"},
  samppct=70,
  partind=True
)
```

## Decision Tree（ディシジョンツリー）

In this code block we do the following:

1. Train the decision tree using the variable listed we defined in the setup phase. We save the decision tree model `tree_model`. It is used in the subsequent step but it could just have easily been used a day, week, or month from now.
1. Score data using the `tree_model` that was created in the previous step
1. Run data step code on the scored output to prepare it for further analysis 

ここでは以下のような処理を行います:

1. セットアップ時に定義した変数を使用して、ディシジョンツリーをトレーニングします。そしてディシジョンツリーモデル `tree_model` を保存します。これは後のステップで使用しますが、今から1日、1週間、または1か月でも利用できます。
1. 前のステップで作成された `tree_model` を使用してデータをスコアリングします
1. スコアリング結果にデータステップコードを実行し、さらに分析する準備をします

```python
sess.decisionTree.dtreeTrain(
  table={
    "name":"hmeq_part",
    "where":"strip(put(_partind_, best.))='1'"
  },
  inputs=all_inputs,
  target="bad",
  nominals=class_vars,
  crit="GAIN",
  prune=True,
  varImp=True,
  missing="USEINSEARCH",
  casOut={"name":"tree_model", "replace":True}
)

# Score （スコア）
sess.decisionTree.dtreeScore(
  table={"name":"hmeq_part"},
  modelTable={"name":"tree_model"},
  casOut={"name":"_scored_tree", "replace":True},
  copyVars={"bad", "_partind_"}
)

# Create p_bad0 and p_bad1 as _dt_predp_ is the probability of event in _dt_predname_
# _dt_predp_ は _dt_predname_ の中にあるイベントの確率です。そこでp_bad0とp_bad1を作成します
sess.dataStep.runCode(code = """
data _scored_tree; 
    length p_bad1 p_bad0 8.;
    set _scored_tree; 
    if _dt_predname_=1 then do; 
        p_bad1=_dt_predp_; 
        p_bad0=1-p_bad1; 
    end; 
    if _dt_predname_=0 then do; 
        p_bad0=_dt_predp_; 
        p_bad1=1-p_bad0; 
    end; 
run;
"""
)
```

## Decision Forest（ディシジョンフォレスト）

In this code block we do the following:

1. Train the decision tree using the variable listed we defined in the setup phase. We save the decision tree model `forest_model`. It is used in the subsequent step but it could just have easily been used a day, week, or month from now.
1. Score data using the `forest_model` that was created in the previous step
1. Run data step code on the scored output to prepare it for further analysis 

ここでは以下のような処理を行います:

1. セットアップ時に定義した変数を使用して、ディシジョンツリーをトレーニングします。そしてディシジョンツリーモデル `forest_model` を保存します。これは後のステップで使用しますが、今から1日、1週間、または1か月でも利用できます。
1. `forest_model` を使用してデータをスコアリングします
1. スコアリング結果にデータステップコードを実行し、さらに分析する準備をします

```python
sess.decisionTree.forestTrain(
  table={
    "name":"hmeq_part",
    "where":"strip(put(_partind_, best.))='1'"
  },
  inputs=all_inputs,
  nominals=class_vars,
  target="bad",
  nTree=50,
  nBins=20,
  leafSize=5,
  maxLevel=21,
  crit="GAINRATIO",
  varImp=True,
  missing="USEINSEARCH",
  vote="PROB",
  casOut={"name":"forest_model", "replace":True}
)

# Score （スコア）
sess.decisionTree.forestScore(
  table={"name":"hmeq_part"},
  modelTable={"name":"forest_model"},
  casOut={"name":"_scored_rf", "replace":True},
  copyVars={"bad", "_partind_"},
  vote="PROB"
)

# Create p_bad0 and p_bad1 as _rf_predp_ is the probability of event in _rf_predname_
# _rf_predp_ は _rf_predname_ の中にあるイベントの確率です。そこでp_bad0とp_bad1を作成します
sess.dataStep.runCode(
  code="data _scored_rf; set _scored_rf; if _rf_predname_=1 then do; p_bad1=_rf_predp_; p_bad0=1-p_bad1; end; if _rf_predname_=0 then do; p_bad0=_rf_predp_; p_bad1=1-p_bad0; end; run;"
)
```

## Gradient Boosting Machine（Gradient Boostingの処理）

In this code block we do the following:

1. Train the decision tree using the variable listed we defined in the setup phase. We save the decision tree model `gb_model`. It is used in the subsequent step but it could just have easily been used a day, week, or month from now.
1. Score data using the `gb_model` that was created in the previous step
1. Run data step code on the scored output to prepare it for further analysis 

ここでは以下のような処理を行います:

1. セットアップ時に定義した変数を使用して、ディシジョンツリーをトレーニングします。 そしてディシジョンツリーモデル `gb_model` を保存します。これは後のステップで使用しますが、今から1日、1週間、または1か月でも利用できます。
1. `gb_model` を使用してデータをスコアリングします
1. スコアリング結果にデータステップコードを実行し、さらに分析する準備をします

```python
sess.decisionTree.gbtreeTrain(
  table={
    "name":"hmeq_part",
    "where":"strip(put(_partind_, best.))='1'"
  },
  inputs=all_inputs,
  nominals=class_vars,
  target=target,
  nTree=10,
  nBins=20,
  maxLevel=6,
  varImp=True,
  missing="USEINSEARCH",
  casOut={"name":"gb_model", "replace":True}
)

# Score （スコア）
sess.decisionTree.gbtreeScore(
  table={"name":"hmeq_part"},
  modelTable={"name":"gb_model"},
  casOut={"name":"_scored_gb", "replace":True},
  copyVars={ target, "_partind_"}
)

# Create p_bad0 and p_bad1 as _gbt_predp_ is the probability of event in _gbt_predname_
# _gbt_predp_は_gbt_predname_の中にあるイベントの確率であるため、p_bad0とp_bad1を作成します
sess.dataStep.runCode(
  code="data _scored_gb; set _scored_gb; if _gbt_predname_=1 then do; p_bad1=_gbt_predp_; p_bad0=1-p_bad1; end; if _gbt_predname_=0 then do; p_bad0=_gbt_predp_; p_bad1=1-p_bad0; end; run;"
)
```

## Neural Network（ニューラルネットワーク）

In this code block we do the following:

1. Train the decision tree using the variable listed we defined in the setup phase. We save the decision tree model `nnet_model`. It is used in the subsequent step but it could just have easily been used a day, week, or month from now.
1. Score data using the `nnet_model` that was created in the previous step
1. Run data step code on the scored output to prepare it for further analysis 
 
ここでは以下のような処理を行います:

1. セットアップ時に定義した変数を使用して、ディシジョンツリーをトレーニングします。 ディシジョンツリーモデル `nnet_model` を保存します。これは後のステップで使用しますが、今から1日、1週間、または1か月でも利用できます。
1. `nnet_model` を使用してデータをスコアリングします
1. スコアリング結果にデータステップコードを実行し、さらに分析する準備をします

```python
sess.neuralNet.annTrain(
  table={
    "name":"hmeq_part",
    "where":"strip(put(_partind_, best.))='1'"
  },
  validTable={
    "name":"hmeq_part",
    "where":"strip(put(_partind_, best.))='0'"
  },
  inputs=all_inputs,
  nominals=class_vars,
  target="bad",
  hiddens={7},
  acts={"TANH"},
  combs={"LINEAR"},
  targetAct="SOFTMAX",
  errorFunc="ENTROPY",
  std="MIDRANGE",
  randDist="UNIFORM",
  scaleInit=1,
  nloOpts={
    "optmlOpt":{"maxIters":250, "fConv":1e-10}, 
    "lbfgsOpt":{"numCorrections":6},
    "printOpt":{"printLevel":"printDetail"},
    "validate":{"frequency":1}
  },
  casOut={"name":"nnet_model", "replace":True}
)

# Score（スコア）
sess.neuralNet.annScore(
  table={"name":"hmeq_part"},
  modelTable={"name":"nnet_model"},
  casOut={"name":"_scored_nn", "replace":True},
  copyVars={"bad", "_partind_"}
)

# Create p_bad0 and p_bad1 as _nn_predp_ is the probability of event in _nn_predname_
# _nn_predp_は_nn_predname_のイベントの中の確率であるため、p_bad0とp_bad1を作成します
sess.dataStep.runCode(
  code="data _scored_nn; set _scored_nn; if _nn_predname_=1 then do; p_bad1=_nn_predp_; p_bad0=1-p_bad1; end; if _nn_predname_=0 then do; p_bad0=_nn_predp_; p_bad1=1-p_bad0; end; run;"
)
```

## Assess Models（モデルの評価）


```python
def assess_model(prefix):
    return sess.percentile.assess(
      table={
        "name":"_scored_" + prefix, 
        "where": "strip(put(_partind_, best.))='0'"
      },
      inputs=[{"name":"p_bad1"}],      
      response="bad",
      event="1",
      pVar={"p_bad0"},
      pEvent={"0"}      
    )

treeAssess=assess_model(prefix="tree")    
tree_fitstat =treeAssess.FitStat
tree_rocinfo =treeAssess.ROCInfo
tree_liftinfo=treeAssess.LIFTInfo

rfAssess=assess_model(prefix="rf")    
rf_fitstat =rfAssess.FitStat
rf_rocinfo =rfAssess.ROCInfo
rf_liftinfo=rfAssess.LIFTInfo

gbAssess=assess_model(prefix="gb")    
gb_fitstat =gbAssess.FitStat
gb_rocinfo =gbAssess.ROCInfo
gb_liftinfo=gbAssess.LIFTInfo

nnAssess=assess_model(prefix="nn")    
nn_fitstat =nnAssess.FitStat
nn_rocinfo =nnAssess.ROCInfo
nn_liftinfo=nnAssess.LIFTInfo
```

## Create ROC and Lift plots (using Validation data) （ROCとLiftプロットの作成（検証データを使用））

#### Prepare assessment results for plotting（プロットの評価結果を準備）


```python
# Add new variable to indicate type of model
# モデルのタイプを表す変数を定義
tree_liftinfo["model"]="DecisionTree"
tree_rocinfo["model"]="DecisionTree"
rf_liftinfo["model"]="Forest"
rf_rocinfo["model"]="Forest"
gb_liftinfo["model"]="GradientBoosting"
gb_rocinfo["model"]="GradientBoosting"
nn_liftinfo["model"]="NeuralNetwork"
nn_rocinfo["model"]="NeuralNetwork"

# Append data（データの追加）
all_liftinfo=rf_liftinfo.append(gb_liftinfo, ignore_index=True).append(nn_liftinfo, ignore_index=True).append(tree_liftinfo, ignore_index=True)
all_rocinfo=rf_rocinfo.append(gb_rocinfo, ignore_index=True).append(nn_rocinfo, ignore_index=True).append(tree_rocinfo, ignore_index=True)
#all_liftinfo=rf_liftinfo.append(tree_liftinfo, ignore_index=True)
#all_rocinfo=rf_rocinfo.append(tree_rocinfo, ignore_index=True)
```

## Print AUC (Area Under the ROC Curve)（AUCの出力（ROC曲線下の面積））


```python
print("AUC (using validation data)".center(80, '-'))
all_rocinfo[["model", "C"]].drop_duplicates(keep="first").sort_values(by="C", ascending=False)
```

## Draw ROC and Lift plots（ROCとリフトプロットの描画）


```python
#/* Draw ROC charts */ 
#/* ROCチャートの描画 */ 
plt.figure()
for key, grp in all_rocinfo.groupby(["model"]):
    plt.plot(grp["FPR"], grp["Sensitivity"], label=key)
plt.plot([0,1], [0,1], "k--")
plt.xlabel("False Postivie Rate")
plt.ylabel("True Positive Rate")
plt.grid(True)
plt.legend(loc="best")
plt.title("ROC Curve (using validation data)")
plt.show()

#/* Draw lift charts */
#/* lift チャートの描画 */
plt.figure()
for key, grp in all_liftinfo.groupby(["model"]):
    plt.plot(grp["Depth"], grp["Lift"], label=key)
plt.xlabel("Depth")
plt.ylabel("Lift")
plt.grid(True)
plt.legend(loc="best")
plt.title("Lift Chart (using validation data)")
plt.show();
```

## End CAS session（CASセッションの終了）

This closes the CAS session freeing resources for others to leverage

以下のコードでCASセッションを閉じ、リソースが開放されます。

```python
sess.close()
```


----

ここまでの内容が Basic Predictive Modeling Example.ipynb で書かれているデモになります。Jupyter Notebookなので、Webブラウザ上でコードを実行して結果を確認できます。ぜひSAS Viyaで体験してみてください。

[SAS for Developers | SAS](https://developer.sas.com/home.html)