StatsFragments

Python, R, Rust, 統計, 機械学習とか

R prcomp での主成分分析結果から元データを復元する

普通はこんなことやる必要ないですが、、、主成分分析 prcomp 関数の結果のみを引数にして、元データ込みの処理を行う関数がどうしても書きたかったので。

# 元データ
head(iris)
#   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1          5.1         3.5          1.4         0.2  setosa
# 2          4.9         3.0          1.4         0.2  setosa
# 3          4.7         3.2          1.3         0.2  setosa
# 4          4.6         3.1          1.5         0.2  setosa
# 5          5.0         3.6          1.4         0.2  setosa
# 6          5.4         3.9          1.7         0.4  setosa

# 数値列のみにフィルタ
df <- iris[c(1, 2, 3, 4)]

このデータに対して主成分分析を行い、得られた結果から元データを復元したい。

主成分分析では元データを分散が最大になる方向に回転させたものが主成分得点、回転を定義する行列が主成分(固有ベクトル)になっているため、主成分得点を主成分(固有ベクトル)と逆に回転すれば元の方向に戻る。また、prcomp デフォルトでは center = TRUE が指定されており、元データの平均値を 0 にする標準化が行われているので、こちらも逆の処理をすれば元データに戻せる。

# 主成分分析実行
pca.result <- prcomp(df)

str(pca.result)
# List of 5
#  $ sdev    : num [1:4] 2.056 0.493 0.28 0.154
#  $ rotation: num [1:4, 1:4] 0.3614 -0.0845 0.8567 0.3583 -0.6566 ...
#   ..- attr(*, "dimnames")=List of 2
#   .. ..$ : chr [1:4] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width"
#   .. ..$ : chr [1:4] "PC1" "PC2" "PC3" "PC4"
#  $ center  : Named num [1:4] 5.84 3.06 3.76 1.2
#   ..- attr(*, "names")= chr [1:4] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width"
#  $ scale   : logi FALSE
#  $ x       : num [1:150, 1:4] -2.68 -2.71 -2.89 -2.75 -2.73 ...
#   ..- attr(*, "dimnames")=List of 2
#   .. ..$ : NULL
#   .. ..$ : chr [1:4] "PC1" "PC2" "PC3" "PC4"
#  - attr(*, "class")= chr "prcomp"

# 主成分と逆方向に回転
original <- pca.result$x %*% t(pca.result$rotation)

# 平均値の標準化を元に戻す
original <- scale(original, center = -pca.result$center, scale = FALSE)
head(original)
#      Sepal.Length Sepal.Width Petal.Length Petal.Width
# [1,]          5.1         3.5          1.4         0.2
# [2,]          4.9         3.0          1.4         0.2
# [3,]          4.7         3.2          1.3         0.2
# [4,]          4.6         3.1          1.5         0.2
# [5,]          5.0         3.6          1.4         0.2
# [6,]          5.4         3.9          1.7         0.4

prcomp(scale=TRUE)標準偏差も標準化して主成分分析した場合は、平均値を戻す前に標準偏差を戻す。

# 主成分分析実行
pca.result <- prcomp(df, scale = TRUE)

# 主成分と逆方向に回転
original <- pca.result$x %*% t(pca.result$rotation)

# 標準偏差の標準化を元に戻す
original <- scale(original, center = FALSE, scale = 1 / pca.result$scale)

# 平均値の標準化を元に戻す
original <- scale(original, center = -pca.result$center, scale = FALSE)
head(original)
#      Sepal.Length Sepal.Width Petal.Length Petal.Width
# [1,]          5.1         3.5          1.4         0.2
# [2,]          4.9         3.0          1.4         0.2
# [3,]          4.7         3.2          1.3         0.2
# [4,]          4.6         3.1          1.5         0.2
# [5,]          5.0         3.6          1.4         0.2
# [6,]          5.4         3.9          1.7         0.4