SPSS Modeler18.5の新機能の ネイティブ Python API

SPSS Modeler18.5の新機能の [ネイティブ Python API](https://www.ibm.com/docs/ja/spss-modeler/18.5.0?topic=spark-native-python-apis)のテストをしてみました。これは、「拡張ノード」のなかでpandasを使ってModelerのデータを読んだり書いたりすることができる機能です。

これは[日本からのリクエスト](https://ibm-data-and-ai.ideas.ibm.com/ideas/MDLR-I-339)が実現したものです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/3df13bc6-1522-9749-b70a-e335bf4cf18b.png)

Modeler18.4以前でも、拡張ノードでPythonを使うことはできましたが、「Python for Spark」のみでした。Sparkを使っていたために、初回起動時はオーバーヘッドがありました。2回目以降の実行ではあまり気にならないのですが、
また、pandasを使いたい場合には、toPandas()で変換するという面倒さとメモリの無駄遣いがありました。

この記事ではネイティブ Python APIが、どのように利用可能かをテストしてみました。

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

https://github.com/hkwd/231229NativePythonExtension/raw/master/231229NativePythonExtensionSample/python-extension-demo_hkwd.str

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

各ノードの利用方法は以下の記事に詳しく書きました。
|アイコン|拡張ノード|
|:----:|:----|
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/edece870-6612-c571-ed14-b234f04f2a8f.png)|[拡張の入力](https://qiita.com/kawada2017/items/72a15c121d196b7f5b0a)|
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/0d6df38a-2773-ed0b-a9d2-1313c99f5f9d.png)|[拡張の変換](https://qiita.com/kawada2017/items/5c58017404ddd08a60eb)|
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/ef1a128f-490e-7b8c-82ae-15ce3e77ea31.png)|[拡張のモデル](https://qiita.com/kawada2017/items/965b5bd6fff90d2cfc02)|
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/73a4ff2a-255e-1e5e-4aec-690df6c9b61b.png)|[拡張の出力](https://qiita.com/kawada2017/items/be3fddcdf7ed11d80b4c)|
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/55cba54b-aac1-07d3-2d6b-ab2ae29f948b.png)|[拡張のエクスポート](https://qiita.com/kawada2017/items/7a4a00c8a0f77efb6f79)|

# バージョンなどの確認
まず「拡張の出力ノード」で、Pythonのバージョンや実体を確認してみます。
「Python」を選択し、「Python Syntax」の欄に以下のスクリプトを記入します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/3ec4f1fa-a1c1-4c8e-674a-796f3bafd7bf.png)


```python:# バージョンなどの確認
import sys
import pprint

print('sys.version: '+sys.version)

print('sys.base_prefix: '+sys.base_prefix)

print('sys.path: ')
pprint.pprint(sys.path)
```

Pythonのバージョンは3.10.7でModelerのインストールディレクトリは配下にある製品同梱のPythonを使っています（Python for Sparkでは別にユーザーが導入したPythonを利用することもできましたが、この機能では製品同梱で固定です）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/74fd7fd5-b3b0-f129-ebb5-25db225038f3.png)

# Python for Sparkは引き続き利用可能
Python for Sparkは引き続き利用可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/82305e3a-4823-23bc-8550-d503cfd755f8.png)

# ネイティブPythonとPython for Sparkとのパフォーマンスの違い
上の単にバージョンを出力するスクリプトを実行した場合で、 ネイティブPythonとPython for Sparkとのパフォーマンスの違いを確認してみたところ、やはり大きな差がありました。Python for Sparkは30-60秒程度の起動のオーバーヘッドがありました。

| |初回経過秒|二回目経過秒|
|:----|----:|----:|
|ネイティブPython|0.63|0.76|
|Python for Spark|61.22|1.39|

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/872dc600-1e7b-e8a6-fca6-64c337894876.png)

# パッケージ導入
パッケージ導入方法は以下の記事に書きました。

ネイティブpythonの拡張ノードでつかうpythonパッケージを導入する 

https://qiita.com/kawada2017/items/9252f93cf59948dd2810


# データ型
各データ型がどのように扱われるかについても調べました。

結論からいうと以下のマッピングになっていました。
|Modelerデータ型|Pythonデータ型|
|--|--|
|整数|int64|
|実数|float64|
|文字列型|str|
|日付|datetime.date|
|タイムスタンプ|datetime64[ns]|
|時間|datetime.time|


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/75fc2e89-d723-11eb-4e35-8261f41cda66.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/40e30d4e-95d9-3c2f-e070-a34ade21b0d9.png)

```python
# ネイティブ Python APIのパッケージ
import modelerpy

#Modelerのデータをpandas Dataframeに読込
modelerData = modelerpy.readPandasDataframe()

#Modelerのデータモデルを取得
modelerDataModel = modelerpy.getDataModel()

#データの表示
print("----modelerData----")
print(modelerData)

#データモデルの表示
print("----modelerDataModel----")
for f in modelerDataModel.getFields():
    print(f.getName()+" "+f.getStorage()+" "+f.getMeasure())

#pandasとしてデータ型確認
print("----modelerData----")
print(modelerData.dtypes)
print(type(modelerData['STR'][0]))
print(type(modelerData['DATE'][0]))
print(type(modelerData['TS'][0]))
print(type(modelerData['TIME'][0]))
```


結果は以下のようになっています。（日本語のコンソール出力が文字化けしていますが、実データは特に化けていません）
```
----modelerData----
   INT  FLOAT  STR        DATE                  TS      TIME
0    1    1.0  ���{��  2000-01-31 2022-01-31 23:59:59  13:20:58
----modelerDataModel----
INT integer continuous
FLOAT real continuous
STR string flag
DATE date continuous
TS timestamp continuous
TIME time continuous
----modelerData----
INT               int64
FLOAT           float64
STR              object
DATE             object
TS       datetime64[ns]
TIME             object
dtype: object
<class 'str'>
<class 'datetime.date'>
<class 'pandas._libs.tslibs.timestamps.Timestamp'>
<class 'datetime.time'>
```

# テンプレート
「インポート」「変換」「モデル作成」「出力」「エクスポート」それぞれにあわせた拡張ノードのテンプレートが自動的に入るようになっています。

例えば「インポート」の場合ですと以下のスクリプトが自動的に入力されます。
```python
###Use this code to export data from Python to Modeler
#import modelerpy
#if modelerpy.isComputeDataModelOnly():
#    outputDataModel = None
###Compute output data model here

#    modelerpy.setOutputDataModel(outputDataModel)
#else:
#    outputData = None
###Compute output data here

#    modelerpy.writePandasDataframe(outputData)

```
ちなみにこれも[日本からのリクエスト](https://ibm-data-and-ai.ideas.ibm.com/ideas/MDLR-I-334)が実現したものです



# その他
* コンソールへの日本語出力は現時点では文字化けしています。ただし、データとして扱う分には問題はありません。
* コンソールは、以前実行の出力が残ってしまうことがあるようです。
* scikitlearnのモデルはストリーム内に保存されるようになりました。外部のフォルダにpickleで保存する必要はありません。ちなみにこれも[日本からのリクエスト](https://ibm-data-and-ai.ideas.aha.io/ideas/MDLR-I-333)が実現しました。


# 参考
#### SPSS Modeler 18.5リリース #SPSS - Qiita 
https://qiita.com/kawada2017/items/b619d5e3db8bb1ff816e