2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ネイティブ Python拡張モデルノード:モデル作成OneClassSVM

Last updated at Posted at 2024-04-12

SPSS Modeler18.5の新機能の ネイティブ Python APIのテストをしてみました。これは、「拡張ノード」のなかでpandasを使ってModelerのデータを読んだり書いたりすることができる機能です。

この記事ではネイティブ Python APIで「拡張モデル」が、どのように利用可能かをテストしてみました。
マニュアルにサンプル・ストリームがついていましたので、これを修正してテストしてみています。

サンプルストリームは以下です。

  • テスト環境
    • Windows 11 64bit
    • Modeler 18.5
    • Python 3.10.7

拡張モデル

OneClassSVMのモデル作成とスコアリング

あらかじめ、以下のコマンドを管理者権限で実行してscikit-learnを導入しておきます

"C:\Program Files\IBM\SPSS\Modeler\18.5\python_venv\Scripts\python.exe" -m pip install scikit-learn

「Python」を選択し、「Python model building Syntax」の欄と「Python model scoring Syntax」の欄に以下のスクリプトを記入します。

image.png

モデルの作成(Python model building Syntax)

#OneClassSVMのモデル作成
###Use this code to import data from Modeler to Python
# ネイティブ Python APIのパッケージ
import modelerpy

import numpy
from sklearn import svm

#前のノードからデータの読み込み
modelerData = modelerpy.readPandasDataframe()
#Modelerのデータモデルを取得
#modelerDataModel = modelerpy.getDataModel()
modelerModel = None
modelName = None

#    build model here
# モデルの作成
#カテゴリ変数をLabelEcodingして数値化、numpyの配列化
encoded_data = modelerData.replace({'Sex': {'M': 0, 'F': 1}, 'BP': {'HIGH':3, 'NORMAL':2, 'LOW':1}, 'Cholesterol': {'HIGH':3, 'NORMAL':2}, 'Drug':{'drugA':1, 'drugB':2, 'drugC':3, 'drugX':4,  'drugY':5}})
training_data = encoded_data.to_numpy()

#OneClassSVMでモデル作成。教師なし学習
modelerModel = svm.OneClassSVM()
modelerModel.set_params(nu=0.1)
modelerModel.fit(training_data)

#モデルをストリーム内に保存
modelName = 'svmmodel'
modelerpy.saveModel(modelerModel, modelName)

「モデルの作成(Python model building Syntax)」のスクリプトを解説します。

まず、modelerpy.readPandasDataframe()で前ノードからのデータを読み込んでいます。

前ノードのデータから、カテゴリ変数の「Sex」「BP」「Cholesterol」「Drug」をLabelEcodingして数値化し、numpyの配列化して学習データを準備しています。

カテゴリ変数をLabelEcodingして数値化、numpyの配列化
encoded_data = modelerData.replace({'Sex': {'M': 0, 'F': 1}, 'BP': {'HIGH':3, 'NORMAL':2, 'LOW':1}, 'Cholesterol': {'HIGH':3, 'NORMAL':2}, 'Drug':{'drugA':1, 'drugB':2, 'drugC':3, 'drugX':4,  'drugY':5}})
training_data = encoded_data.to_numpy()

OneClassSVMでモデル作成を作成しています。ここは普通のscikitlearnのモデリングです。

OneClassSVMでモデル作成。教師なし学習
modelerModel = svm.OneClassSVM()
modelerModel.set_params(nu=0.1)
modelerModel.fit(training_data)

モデルの名前をつけて、saveModelのAPIでストリーム内に保存しています。
Python for Sparkでは、scikitlearnのモデルはストリーム内に保存できなかったために、どこかのフォルダにpickleで保存していましたが、そういう作業が不要です。

モデルをストリーム内に保存
modelName = 'svmmodel'
modelerpy.saveModel(modelerModel, modelName)

モデルのスコアリング(Python model scoring Syntax)

#OneClassSVMのスコアリング
###Use this code to transfer data between Modeler and Python
# ネイティブ Python APIのパッケージ
import modelerpy

import numpy
from sklearn import svm

field_outlier = 'Outlier'
field_dist_hp = 'DIST_HP'

#データモデルの参照時
if modelerpy.isComputeDataModelOnly():
    modelerDataModel = modelerpy.getDataModel()
    outputDataModel = None

    #Compute output data model here
    #出力データモデルの設定。スコアリング結果を出力するOutlier列とDIST_HP列を追加
    outputDataModel = modelerDataModel
    outputDataModel.addField(modelerpy.Field(field_outlier, "real", measure="flag"))
    outputDataModel.addField(modelerpy.Field(field_dist_hp, "real", measure="continuous"))
    modelerpy.setOutputDataModel(outputDataModel)

#データ出力時
else:
    modelerData = modelerpy.readPandasDataframe()
    modelName = None

    #モデルをストリームから読み出し
    modelName = 'svmmodel'
    modelerModel = modelerpy.loadModel(modelName)
    outputData = None

    #データの出力
    outputData = modelerData
    #カテゴリ変数をLabelEcodingして数値化、numpyの配列化
    encoded_data = modelerData.replace({'Sex': {'M': 0, 'F': 1}, 'BP': {'HIGH':3, 'NORMAL':2, 'LOW':1}, 'Cholesterol': {'HIGH':3, 'NORMAL':2}, 'Drug':{'drugA':1, 'drugB':2, 'drugC':3, 'drugX':4,  'drugY':5}})
    score_data = encoded_data.to_numpy()

    #スコアリング
    outlier = modelerModel.predict(score_data)
    dist_hp = modelerModel.decision_function(score_data)
    outputData[field_outlier] = outlier
    outputData[field_dist_hp] = dist_hp
    #データの出力
    modelerpy.writePandasDataframe(outputData)

「モデルのスコアリング(Python model scoring Syntax)」のスクリプトを解説します。
以下でスコアリングで追加される列名を定義しています。

field_outlier = 'Outlier'
field_dist_hp = 'DIST_HP'

大きくはデータモデルの処理とデータ自体の処理の二つに分かれています。

処理の分岐

「データモデルの処理」と「データ自体の処理」の分岐を以下のif文で行っています。

if modelerpy.isComputeDataModelOnly()

modelerpy.isComputeDataModelOnly():のif文は、後続のノードがデータモデルを参照する場合に実データを用意しなくていいための分岐になります。Modelerは、後続のノードを接続した際に前のノードのデータモデルを参照します。例えば「フィルター」ノードを接続した場合にはデータは必要ありませんが、「列名」の情報は必要になります。このif文をなくしても動作はしますが、列名などのデータモデルを参照したいだけなのにデータの読み込みが行われてしまうため、無駄な処理が動いてしまいます。
なお、このif文は、「拡張の変換」ノードと「拡張モデル」ノードといった後続ノードが必要なノードでも、同様に使われます。

データモデルの処理

modelerDataModel = modelerpy.getDataModel()で前のノードからデータモデルを取得しています。

以下でスコアリングで追加される列のメタデータをaddFieldで追加しています。

出力データモデルの設定。スコアリング結果を出力するOutlier列とDIST_HP列を追加
outputDataModel = modelerDataModel
outputDataModel.addField(modelerpy.Field(field_outlier, "real", measure="flag"))
outputDataModel.addField(modelerpy.Field(field_dist_hp, "real", measure="continuous"))

modelerpy.setOutputDataModel(outputDataModel)で後続ノードに渡すデータモデルを設定しています。

スコアリングの処理

modelerpy.readPandasDataframe()で前ノードからのデータを読み込んでいます。

以下で、ストリーム内に保存したOneClassSVMのモデルを読み出しています。

モデルをストリームから読み出し
modelName = 'svmmodel'
modelerModel = modelerpy.loadModel(modelName)

以下で、前ノードのデータから、カテゴリ変数をLabelEcodingして数値化、numpyの配列化してスコアリングデータを準備しています

カテゴリ変数をLabelEcodingして数値化、numpyの配列化
encoded_data = modelerData.replace({'Sex': {'M': 0, 'F': 1}, 'BP': {'HIGH':3, 'NORMAL':2, 'LOW':1}, 'Cholesterol': {'HIGH':3, 'NORMAL':2}, 'Drug':{'drugA':1, 'drugB':2, 'drugC':3, 'drugX':4,  'drugY':5}})
score_data = encoded_data.to_numpy()

以下で、スコアリングを行っています。
predictで外れ値化どうかのスコアを算出し、decision_functionで距離のスコアを算出しています。

スコアリング
outlier = modelerModel.predict(score_data)
dist_hp = modelerModel.decision_function(score_data)
outputData[field_outlier] = outlier
outputData[field_dist_hp] = dist_hp

modelerpy.writePandasDataframe(outputData)で後続のノードにデータを出力しています。

モデリングノードの実行結果

モデリングノードを実行すると、以下のように、「拡張モデル」のスコアリングノードが自動生成されます。また、「シンタックス」には「拡張モデル」のモデリングノードの「Python model scoring Syntax」に記述したPythonスクリプトがそのままコピーされます。
一応「編集」は可能ですが、「拡張モデリング」ノードとコードが食い違っていると後で混乱すると思いますので、開発・テスト用と考えるのがよいと思います。
image.png

スコアリングノードの実行結果

「テーブル」ノードを接続し、実行すると、スコアリング結果が「Outlier」、「DIST_HP」の列に書き出されていることがわかります。
image.png

2
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?