こんばんは,@PKです.
今日はKNIMEの主成分分析(Principal Component Analysis : PCA)のノードを使って,主成分スコアや固有ベクトル,累積寄与率を算出してみます.
以前からKNIMEのPCAノードを使用していたのですが,累積寄与率などが直接出てこないので,今回まとめてみました.
また,おまけですが,PCAノードを使わずに「R snippet」でコードを書いて同様の結果を出力してみます.
PCAとは
ご存知の方も多いと思います…
主成分分析(しゅせいぶんぶんせき、英: principal component analysis; PCA)は、相関のある多数の変数から相関のない少数で全体のばらつきを最もよく表す主成分と呼ばれる変数を合成する多変量解析の一手法。データの次元を削減するために用いられる。 https://ja.wikipedia.org/wiki/%E4%B8%BB%E6%88%90%E5%88%86%E5%88%86%E6%9E%90
PCAについては,ここではあまり詳しくは触れませんが,自分が勉強した際にとてもわかりやすくまとめられていた記事を以下に示します.
主成分分析(PCA)の累積寄与率で見る特徴量エンジニアリング【python】 - ギークなエンジニアを目指す男
Rのprcomp関数で主成分分析
まずKNIMEのノードの説明をする前には,Rのprcomp関数でPCAを行い,取得できるデータを確認します.
題材としては一般的なirisのデータを使用しました.
prcomp関数でPCAを行った結果に対して,summary関数を使うと,標準偏差(Standard deviation),寄与率(Proportion of Variance ),累積寄与率(Cumulative Proportion)がそれぞれ表示されます.
> column_list <- c("Sepal.Length","Sepal.Width","Petal.Length","Petal.Width") > iris.pc<-prcomp(iris[, column_list]) > summary(iris.pc) Importance of components: PC1 PC2 PC3 PC4 Standard deviation 2.0563 0.49262 0.2797 0.15439 Proportion of Variance 0.9246 0.05307 0.0171 0.00521 Cumulative Proportion 0.9246 0.97769 0.9948 1.00000
また,主成分分析の結果(主成分スコア)はiris.pc$xで表示することができます.
> head(iris.pc$x) PC1 PC2 PC3 PC4 [1,] -2.684126 -0.3193972 0.02791483 0.002262437 [2,] -2.714142 0.1770012 0.21046427 0.099026550 [3,] -2.888991 0.1449494 -0.01790026 0.019968390 [4,] -2.745343 0.3182990 -0.03155937 -0.075575817 [5,] -2.728717 -0.3267545 -0.09007924 -0.061258593 [6,] -2.280860 -0.7413304 -0.16867766 -0.024200858
主成分(固有ベクトル)を知りたい場合は,iris.pc$rotationで表示することができます.
> iris.pc$rotation PC1 PC2 PC3 PC4 Sepal.Length 0.36138659 -0.65658877 0.58202985 0.3154872 Sepal.Width -0.08452251 -0.73016143 -0.59791083 -0.3197231 Petal.Length 0.85667061 0.17337266 -0.07623608 -0.4798390 Petal.Width 0.35828920 0.07548102 -0.54583143 0.7536574
KNIMEでもこの辺の値を取得できれば,取り合えずRのPCAと同じことができていることがわかります.
KNIME Workflowの概要
それでは,今回のKNIME Workflowの概要を以下に示します.
上青点線の部分で,PCAノードを使って,主成分分析を行っています.
また,下赤点線の部分はおまけでRノードを使った主成分分析です.
Rノードで同じ操作を行うことで,KNIMEのPCAノードの理解が深まったので,同じ操作を行っています.
KNIMEのPCAノードを使って主成分分析
それでは,本題です. KNIMEでPCAをする際は,以下のノードを使用します.
PCA — NodePit
PCA Compute — NodePit
PCA Apply — NodePit
「PCA」と「PCA Compute」と「PCA Apply」何が違うの???と自分は最初に思いました.「PCA」は指定されたデータに対してPCAを行い,主成分スコアだけを表示するノードです.
「PCA Compute」も同様にデータに対するPCAを行いますが,ここではモデルを作るだけで,実際には「PCA Apply」によってPCAを実行します.
Components of PCA dimensions? - KNIME Analytics Platform - KNIME Community Forum
この記事でも言われていますが,「PCA」だけだと固有ベクトルや累積寄与率の数字は出てこないので,「PCA Compute」と「PCA Apply」を使用するほうが望ましいと思います.
KNIME WorkflowのPCAノードに関する部分について,以下に詳細を示します.
「PCA applay」と「PCA compute」については,主成分分析を行う列を選んで実行するだけです.
「PCA compute」では主成分をいくつにするか選択することができます.
「PCA Compute」を実行すると下左表のような主成分スコアを得ることができました.
「Color Manager」で種ごとに色を付けて「Scatter Plot」で可視化した図が下右図です.
続いて固有ベクトルや累積寄与率ですが,こちらは「PCA Compute」の2番目のポート(Spectral Decomposition)からデータを得ることができます.
固有ベクトルについては,「Column Filter」で固有値を除いて,「Transpose」で行列を入れ替えて,カラム名をRと同じく「"PC1","PC2","PC3","PC4"」そろえると,iris.pc$rotationの結果と一致しました.
一方で,累積寄与率については直接は出てこないようですので,少し計算をして算出します.
まず,「Math Formula」で固有値から寄与率を計算します.
$eigenvalue$/COL_SUM($eigenvalue$)
続いて,「Moving Aggregation」というノードを使って,数値を足し合わせます.(このノード,知らなかったので勉強になりました.)
Moving Aggregation — NodePit
その結果,累積寄与率を算出することができました!
おまけ(Rノードで主成分分析)
おまけで,Rノードで同じように主成分スコア・固有ベクトル・累積寄与率を出したので,簡単に示しておきます.
主成分スコアについては,iris.pc$xを出力しました.
#R snippet column_list <- c("Sepal.Length","Sepal.Width","Petal.Length","Petal.Width") iris.pc<-prcomp(knime.in[, column_list]) Species <- as.character(knime.in$"Species") summary(iris.pc) results<-data.frame(Species,iris.pc$x) knime.out <- results
続いて,固有ベクトルについてはiris.pc$rotationで求めました.
#R snippet column_list <- c("Sepal.Length","Sepal.Width","Petal.Length","Petal.Width") iris.pc<-prcomp(knime.in[, column_list]) Species <- as.character(knime.in$"Species") summary(iris.pc) results <- data.frame(iris.pc$rotation) knime.out <- results
主成分スコアと固有ベクトルを出力するのは,R素人の自分でも簡単でした.
続いて累積寄与率についてですが,以下のように出力しました.
#R snippet column_list <- c("Sepal.Length","Sepal.Width","Petal.Length","Petal.Width") iris.pc<-prcomp(knime.in[, column_list]) Species <- as.character(knime.in$"Species") summary(iris.pc) stats:::print.summary.princomp vars <- iris.pc$sdev^2 vars <- vars/sum(vars) Cumulative_Proportion <- cumsum(vars) name <- names(data.frame(summary(iris.pc)$rotation)) names(Cumulative_Proportion) <- name knime.out <- data.frame(Cumulative_Proportion)
当たり前かもしれないのですが,Summary関数で出てきたCumulative Proportionは,そのままでは取ってこれません(気づくのに時間がかかった…)
同じ事を質問している方がいて...
pca - How to get "proportion of variance" vector from princomp in R - Stack Overflow
Its calculated in the print method, and is not returned. Look at stats:::print.summary.princomp ti see where it is generated.
stats:::print.summary.princompを実行して確認をすると,ちゃんと書いてありました.
> stats:::print.summary.princomp function (x, digits = 3L, loadings = x$print.loadings, cutoff = x$cutoff, ...) { vars <- x$sdev^2 vars <- vars/sum(vars) cat("Importance of components:\n") print(rbind(`Standard deviation` = x$sdev, `Proportion of Variance` = vars, `Cumulative Proportion` = cumsum(vars))) if (loadings) { cat("\nLoadings:\n") cx <- format(round(x$loadings, digits = digits)) cx[abs(x$loadings) < cutoff] <- strrep(" ", nchar(cx[1, 1], type = "w")) print(cx, quote = FALSE, ...) } invisible(x) } <bytecode: 0x0000017dc9a49250> <environment: namespace:stats> >
というわけで,標準偏差から計算をして求めました.
おわりに
主成分分析(PCA)ノードを使って,主成分スコア・固有ベクトル・累積寄与率を出すことを紹介しました.
RノードでPCAで何をやっているのか確認してからKNIMEのノードを使うと,より意味が分かって勉強になると感じたので,今後もRの勉強は続けていきます.