SPSS Modelerの拡張ノードでモデル作成する際の注意点

# 拡張モデルノードで作成したモデルの予測結果がおかしい

みなさんこんにちは。今回は拡張モデルノードでモデル作成後に予測結果をスコアリングノードで出力させたときに、結果が予想と異なり、かなりはまった事例を紹介します。

## 1. PLSモデルの予測結果がおかしい。。

https://qiita.com/harrowharrow16/items/74ca3f18b27ca12f3a08

上記の記事からの続きでモデルを実装していたのですが、なぜか予測結果がおかしくなる事象が発生しました。

### ①. 拡張ノードでPLSモデルを作成して結果を確認

拡張モデルノードでモデルを作成して、同じ学習データをそのまま生成されたスコアリングノードに投入して結果を精度分析ノードで確認した結果が下記画像です。$PLS-octaneが予測値です。
※.octane値を各スペクトルフィールドの値で予測するPLS回帰モデルです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/201d027b-0d70-4cdf-948e-2d100a960b1e.png)


線形相関が下がっていることに？と思ったのですが、何より誤差がひどい。
テーブルノードで予測値を確認したのが、次の画像です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/1710eb00-a1cb-4edd-9b93-96259c786f0c.png)

なんで？？予測値が12??。実測値は85等なので。おかしい。。



## 2. 原因調査を実施


### ①. 学習時とスコアリング時のモデルを比較

さて、これはおかしいと思いモデルの内容を確認しました。
考えられることとしては、

1. そもそも作成したモデルの精度が低い

1. 学習モデルとスコアリング用モデルの整合性がとれていない？
    ①. 学習モデルとスコアリング用モデルは同一のものか？
    ②. 学習モデルとスコアリング用モデルの回帰係数は同じか？
    ③. 学習モデルとスコアリング用モデルの予測値は同じか？
    ④. 入力データは正しいか？

上記の内容を確認しました。

#### i.学習モデルの精度確認

使っていたストリームの全体は以下の通りです。これは、前回の記事で作成したストリームとほぼ同じです。
モデル作成用の部分が追加されただけです。

まずは、前回と同様に拡張の出力ノードでモデルの確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/59568ebc-2d91-499c-ae95-011a6303092f.png)

n_components = 6 で作成すると以下の通りの精度です。これは、同じですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/fd2c3405-e46a-4f1b-972c-2621ec256816.png)

続いて拡張モデルノードでの精度を確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/bf879355-82a0-455d-b431-9dea8e0f5294.png)

ん？精度が違いいますね。
ただ、スコアリング時のような相関係数や誤差ほどではないので、この時点では気にしていませんでした。
※.ここがまずかったです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/d9e36569-2013-4995-9a35-b6902372749d.png)


#### ii.学習モデルとスコアリング用モデルの整合性確認
もしかすると、学習モデルは大丈夫だけど、スコアリング用モデルとしてロードした際に、
何か不具合でうまくロードできていないのでは？と考え回帰係数や、モデル詳細を確認しました。

モデル作成時の詳細は以下の通り
モデルのタイプ、n_components、回帰係数になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/ac3aa07c-3bfd-4322-a589-a6a86f2fbe50.png)

つづいてスコアリング用にロードしたモデルの詳細

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/61b5363b-8108-457f-81a3-dd191801c788.png)

まったく一緒です。保存したモデルを正常にロードできています。


#### iii.学習モデルとスコアリング用モデルの予測値の確認
ストリームを見てもらえばわかる通り、まったく同じデータを投入しています。
なので、予測値が異なることはないと思います。が

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/92726349-8e92-4247-95de-cdf390366210.png)

まずは、モデル作成時の"octane"の予測値
88や85など、12などの数値は見当たりません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/9de34781-18f2-4bd3-b441-7ffcb303c06e.png)

つづいて、スコアリング時の予測値
あーーー。やっぱり12とかになっていますね。これはおかしい。
モデルは一緒で、データも一緒のはず？なのに予測値が違う。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/50746e34-a73d-4ab4-8dd9-2ab04e0fbf21.png)



#### iv.　学習時とスコアリング時の入力データの確認
なんで？

さて、こうなるとモデルに投入したデータが異なることが一番考えられます。
そこで、確認してみました。

まず、データ投入前にテーブルノードで確認
下記画像のように、予想通りの入力データです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/bbb063b7-993b-47cf-a5f4-14ffa613fcbe.png)


目的変数の "octane" が一番最初にあり、そこから61個の説明変数であるスペクトルフィールドがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/96d7c4e5-5cef-4988-bb2a-735dd8053f7a.png)

このデータを入力データとしています。
さて、PLSモデルを作成するときに、拡張ノードのPythonでは以下の処理をしています。

```python: データ加工

#-------------------------------------------------------
# データ入力
#-------------------------------------------------------
# 事前にデータ区分で学習・テストデータは分けているのでそのまま入力
# Pandasで入力
modelerData = modelerpy.readPandasDataframe()

# 説明変数 - NIR.900 rm以降の列を全て
xdata = modelerData.iloc[:, 1:]  # 2列目（index=1）以降を選択

# 目的変数 - octane
ydata = modelerData['octane']

```

目的変数は、ydata = modelerData['octane']　と、そのまま "octane"フィールドを指定しています。

**が**

説明変数は、フィールド名指定ではなく、xdata = modelerData.iloc[:, 1:]  と、
2列目（index=1）以降を全てを選択するように記述しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/d6064d36-a1f6-4833-9e99-7fce3f31d251.png)

さて、拡張モデルノードで入力変数である、xdata の中身を出力してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/079ee1fe-d90d-4a55-a67c-edcf491a734b.png)

つづいて、スコアリングナゲットでの xdata の中身です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/d82d696c-edd6-48a2-a327-762909aa0562.png)

ここで、やっと気づきました。
フィールドがずれている。
"octane"フィールドが一番最後に移動したため、"NIR 1126 nm"が除外され(1列目になってしまったため)、それ以外(octaneも含め)が説明変数となってしまいました。

ええー？？
スコアリング時は、予想通りの説明変数のフィールドになっています。こちらは問題なし。
問題は、モデル作成時です。なぜか、"octane" が一番最後にいますね。そして、フィールドの"NIR 1126 nm"がなく、"NIR 1128 nm"からになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/2588158d-f658-4d64-9b65-487be718babf.png)

モデル作成時の説明変数が違うので、精度も違えば、予測値も違うはずですよ。
でもなぜ？


#### v.　学習時とスコアリング時の入力データの差異の原因（あくまで個人の見解です。）

目的変数の"octane"が一番最後に移動していることで、ピンときました。
ここの、特徴量選択ノードのところで、フィールドのロールを設定していました。
"octane"は **"対象"（目的変数）** にロールを設定しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/8b34c90f-096b-421a-802e-01d855865ebd.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/a3da8530-acab-4e4e-b03f-4bebce1cc305.png)





検証のために、"NIR 1128 nm" を"対象"にして、拡張モデルノードに投入し入力データ全てを確認すると

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/79f2a061-ece0-4f4d-a61e-31bed6309133.png)

下記画像の通りに、"octane"の位置はそのままで、"NIR 1128 nm"は一番最後に移動しています。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/878a2569-5ebd-43eb-9c4a-9c27b8d09266.png)

スコアリング時は位置は変化なく正常に入力されていますね。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/6cc57b89-7a6f-4a2b-8fe7-78f5cefa39fe.png)


もう、これが原因でしょう！
フィールドが勝手に違う順番になってしまったため、モデル作成時の説明変数が変わってしまったためです。

このフィールド順が変わってしまうことですが、仕様なのか？は分かりません。とほほ。


気を取り直して、最後に修正して確認すると、精度・予測値ともに想定通りの結果となりました。
"octane"が一番最後の列なので、それを除外したものを説明変数としました。

```python: 説明変数設定
# 説明変数 - 一番最後のoctaneを除いた全て
xdata = modelerData.iloc[:, :-1]  # 最後の列を除外
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/1bc0ae66-c1d4-4400-930c-0f4dcf2877e2.png)



## 3. 原因についてまとめ
原因については、検証した範囲でまとめると、

1. 環境
    ①. SPSS Modeler v18.5 / v18.6 (ともにWindows版)で発生を確認しました。

2. 発生する問題
    ①. 入力フィールドのロール設定が **"対象"** の場合、拡張モデルノードで
       modelerData = modelerpy.readPandasDataframe()
       というように、データ入力した場合、ロールが"対象"のフィールドが **一番最後へ移動** する。
    
3. 発生するノード
    ①.問題の発生するのは、**拡張モデルノード** の **モデル作成のシンタックス**です。
      ※.スコアリングシンタックスでは発生しないようです。
    ②.言語は、**Python** です。（R, Python for Sparkでは確認しておりません。)
    

みなさん、気をつけましょう。

## 4. 最後に
次回は、その２ モデルを実装編を記載する予定です。
あと、SPSS Statisticsと連携することで、拡張ノードでなくてもPLSを実装できます。そちらも紹介する予定です。


https://qiita.com/harrowharrow16/items/74ca3f18b27ca12f3a08


# 参考

SPSS Modeler ノードリファレンス目次

https://qiita.com/416nishimaki/items/503037195081d3323eee

SPSS Modeler 逆引きストリーム集

https://qiita.com/416nishimaki/items/4bf813e6cba84b2a1008

SPSS funさん記事集

https://qiita.com/spssfun2017

SPSS連載ブログバックナンバー

https://qiita.com/416nishimaki/items/24c054defbe7280bcf0e

SPSSヒモトクブログ

https://www.ibm.com/blogs/solutions/jp-ja/category/bigdata-analytics/spss-modeler-himotoku/

今後は、ヒモトクブログなどは以下のTechXchangeのコミュニティに統合される予定です。
ご興味がある方は、ぜひiBM IDを登録して参加してみてください！！！お待ちしています。

IBM TechXchange Data Science Japan

https://community.ibm.com/community/user/ai-datascience/communities/community-home?communitykey=5e746c4e-1ae3-4db4-a23c-153cf231fe73