概要
Nimからsklearnをつかって主成分分析を行う手順をまとめました。
言わずとしれたsklearnを使うことで主成分分析を数行で行うことができますので、Nimから実行するためnimpyというライブラリをつかって実行してみます。実際にsklearnを使って主成分分析を行う部分はPythonで記述します。
nimpyでPythonを呼ぶ方法については以前やったのでその応用になります。
Nimpyでnimからpythonを呼ぶ
Python側の準備
pyenv等で任意のPythonをいれる際に例のごとく(上記の記事を参考に)、CONFIGURE_OPTS="--enable-shared"
を付与してlibpythonが生成されるようにします。
そしてpoetry等を使ってsklearnをいれます。
[tool.poetry]
name = "nimpy_pca"
version = "0.1.0"
description = ""
authors = ["Your Name <you@example.com>"]
[tool.poetry.dependencies]
python = "^3.7"
numpy = "^1.18"
scikit-learn = "^0.22.2"
[tool.poetry.dev-dependencies]
[build-system]
requires = ["poetry>=1.0"]
build-backend = "poetry.masonry.api"
sklearnでのPCAの書き方がnimから呼ぶのが難しいため、pythonで処理を書きます。(nimpyではメソッドをcall仕組みなのでイニシャライザのような書き方や戻り値のない構文が使えない)
型の受け渡しを簡略化するためにJSONを使ってデータや結果のやり取りを行うようにしています。
from sklearn.decomposition import PCA
import numpy as np
import json
def pca(json_text):
data = json.loads(json_text)
pca = PCA(n_components=2)
A = np.array(data)
pca.fit(A)
return {
"components": pca.components_.tolist(),
"varianceRatio": pca.explained_variance_ratio_.tolist()
}
nimpyでNimからPythonを呼ぶ
まず、poetryで入れたsklearnが読み込みできるようにlibpythonのpathを指定します。
import nimpy
import nimpy/py_lib as pyLib
pyLib.pyInitLibPath("/root/.pyenv/versions/3.7.7/lib/libpython3.7m.so")
また、先程つくったPythonを読み込めるようにファイルのある場所のpathを追加します。
discard pyImport("sys").path.append("/workspace/src")
そしてJSONデータをつかって先程のメソッドにデータを渡します。 toJson
をつかって 戻り値の PyObject
という型からJsonNode型に変換しています。
let pcaResult = pyImport("pca.py").callMethod("pca", json).toJson
あとはpcaResultにはいっている値を展開すれば完成です。
import sugar
let projectedValues = datas.map(data =>
pcaResult["components"].getElems.map(c => c.getElems.zip(data).map(n => n[0].getFloat * n[1]).foldl(a + b))
)
まとめ
pyImport
のパスの指定の仕方やpythonファイルの名前衝突などにつまりましたが、pythonの読み込みがこちらのやり方できました。
これを応用すれば、他の統計処理や線形処理もPythonにまかせて簡単に実行することができそうです。