@ amoeba 's 및 @ttnphns 'post 업 보팅을 고려하십시오 . 당신의 도움과 아이디어에 감사드립니다.
다음은 R 의 Iris 데이터 세트 , 특히 처음 세 변수 (열) 에 의존합니다 Sepal.Length, Sepal.Width, Petal.Length
.
행렬도는 결합 로딩 플롯 콘크리트 처음 두 - (표준화가 고유 벡터) 하중 및 점수 플롯 (주성분에 대하여 플롯 회전 팽창 데이터 점). @amoeba 는 동일한 데이터 세트 를 사용하여 첫 번째 및 두 번째 주요 구성 요소 의 점수 도표 의 3 가지 가능한 정규화 와 초기 변수 의 적재 도표 (화살표) 의 3 가지 정규화를 기반으로 9 가지 가능한 PCA biplot 조합을 설명 합니다. R이 이러한 가능한 조합을 처리하는 방법을 보려면 방법을 살펴 보는 것이 흥미 롭습니다 biplot()
.
먼저 선형 대수를 복사하여 붙여 넣을 준비가되었습니다.
X = as.matrix(iris[,1:3]) # Three first variables of Iris dataset
CEN = scale(X, center = T, scale = T) # Centering and scaling the data
PCA = prcomp(CEN)
# EIGENVECTORS:
(evecs.ei = eigen(cor(CEN))$vectors) # Using eigen() method
(evecs.svd = svd(CEN)$v) # PCA with SVD...
(evecs = prcomp(CEN)$rotation) # Confirming with prcomp()
# EIGENVALUES:
(evals.ei = eigen(cor(CEN))$values) # Using the eigen() method
(evals.svd = svd(CEN)$d^2/(nrow(X) - 1)) # and SVD: sing.values^2/n - 1
(evals = prcomp(CEN)$sdev^2) # with prcomp() (needs squaring)
# SCORES:
scr.svd = svd(CEN)$u %*% diag(svd(CEN)$d) # with SVD
scr = prcomp(CEN)$x # with prcomp()
scr.mm = CEN %*% prcomp(CEN)$rotation # "Manually" [data] [eigvecs]
# LOADINGS:
loaded = evecs %*% diag(prcomp(CEN)$sdev) # [E-vectors] [sqrt(E-values)]
1. 로딩 도표 (화살표) 재생 :
@ttnphns 의이 게시물 의 기하학적 해석 은 많은 도움이됩니다. 게시물의 다이어그램 표기가 유지되었습니다. 는 주제 공간 의 변수를 나타냅니다 . h ' 는 궁극적으로 그려진 대응하는 화살표이고; 좌표 a 1 및 a 2 는 PC 1 및 PC 2에 대한 변수 V 를 로드하는 구성 요소입니다 .VSepal L.
h′a1a2VPC1PC2
PC 1에Sepal L.
대한 변수의 구성 요소 는 다음과 같습니다.PC1
a1=h⋅cos(ϕ)
이는의 경우 점수 에 대한 -하자 그들을 호출 S 1 - 그래서 표준화되어 자신의PC1S1
V⋅S1∥S1∥=∑n1scores21−−−−−−−−−√=1V⋅S1
a1=V⋅S1=∥V∥∥S1∥cos(ϕ)=h×1×⋅cos(ϕ)(1)
이후 ,∥V∥=∑x2−−−−√
Var(V)−−−−−√=∑x2−−−−√n−1−−−−−√=∥V∥n−1−−−−−√⟹∥V∥=h=var(V)−−−−−√n−1−−−−−√.
마찬가지로,
∥S1∥=1=var(S1)−−−−−√n−1−−−−−√.
방정식으로 돌아 가기 ,(1)
a1=h×1×⋅cos(ϕ)=var(V)−−−−−√var(S1)−−−−−√cos(θ)(n−1)
r n - 1cos(ϕ) , 따라서 고려 될 수있는 피어슨 상관 계수 , , I는의 주름 이해하지 못하고 있다는 경고와 인자.rn−1
빨간색 화살표가 파란색으로 중복되고 겹칩니다. biplot()
par(mfrow = c(1,2)); par(mar=c(1.2,1.2,1.2,1.2))
biplot(PCA, cex = 0.6, cex.axis = .6, ann = F, tck=-0.01) # R biplot
# R biplot with overlapping (reproduced) arrows in blue completely covering red arrows:
biplot(PCA, cex = 0.6, cex.axis = .6, ann = F, tck=-0.01)
arrows(0, 0,
cor(X[,1], scr[,1]) * 0.8 * sqrt(nrow(X) - 1),
cor(X[,1], scr[,2]) * 0.8 * sqrt(nrow(X) - 1),
lwd = 1, angle = 30, length = 0.1, col = 4)
arrows(0, 0,
cor(X[,2], scr[,1]) * 0.8 * sqrt(nrow(X) - 1),
cor(X[,2], scr[,2]) * 0.8 * sqrt(nrow(X) - 1),
lwd = 1, angle = 30, length = 0.1, col = 4)
arrows(0, 0,
cor(X[,3], scr[,1]) * 0.8 * sqrt(nrow(X) - 1),
cor(X[,3], scr[,2]) * 0.8 * sqrt(nrow(X) - 1),
lwd = 1, angle = 30, length = 0.1, col = 4)
가볼만한 곳:
- 화살표는 원래 변수와 처음 두 주성분에 의해 생성 된 점수와의 상관 관계로 재현 될 수 있습니다.
- 또는 @amoeba의 게시물에 로 표시된 두 번째 행의 첫 번째 플롯에서와 같이 얻을 수 있습니다 .V∗S
또는 R 코드에서 :
biplot(PCA, cex = 0.6, cex.axis = .6, ann = F, tck=-0.01) # R biplot
# R biplot with overlapping arrows in blue completely covering red arrows:
biplot(PCA, cex = 0.6, cex.axis = .6, ann = F, tck=-0.01)
arrows(0, 0,
(svd(CEN)$v %*% diag(svd(CEN)$d))[1,1] * 0.8,
(svd(CEN)$v %*% diag(svd(CEN)$d))[1,2] * 0.8,
lwd = 1, angle = 30, length = 0.1, col = 4)
arrows(0, 0,
(svd(CEN)$v %*% diag(svd(CEN)$d))[2,1] * 0.8,
(svd(CEN)$v %*% diag(svd(CEN)$d))[2,2] * 0.8,
lwd = 1, angle = 30, length = 0.1, col = 4)
arrows(0, 0,
(svd(CEN)$v %*% diag(svd(CEN)$d))[3,1] * 0.8,
(svd(CEN)$v %*% diag(svd(CEN)$d))[3,2] * 0.8,
lwd = 1, angle = 30, length = 0.1, col = 4)
또는 아직 ...
biplot(PCA, cex = 0.6, cex.axis = .6, ann = F, tck=-0.01) # R biplot
# R biplot with overlapping (reproduced) arrows in blue completely covering red arrows:
biplot(PCA, cex = 0.6, cex.axis = .6, ann = F, tck=-0.01)
arrows(0, 0,
(loaded)[1,1] * 0.8 * sqrt(nrow(X) - 1),
(loaded)[1,2] * 0.8 * sqrt(nrow(X) - 1),
lwd = 1, angle = 30, length = 0.1, col = 4)
arrows(0, 0,
(loaded)[2,1] * 0.8 * sqrt(nrow(X) - 1),
(loaded)[2,2] * 0.8 * sqrt(nrow(X) - 1),
lwd = 1, angle = 30, length = 0.1, col = 4)
arrows(0, 0,
(loaded)[3,1] * 0.8 * sqrt(nrow(X) - 1),
(loaded)[3,2] * 0.8 * sqrt(nrow(X) - 1),
lwd = 1, angle = 30, length = 0.1, col = 4)
@ttnphns 또는 @ttnphns의 다른 정보 게시물에 대한 기하학적 설명 과 연결 .
또한 텍스트 레이블의 중심이 있어야 할 곳에 화살표가 그려져 있어야합니다! 그런 다음 플로팅하기 전에 화살표에 0.80.8을 곱합니다. 즉, 모든 화살표는 텍스트 레이블과 겹치지 않도록하기 위해 필요한 것보다 짧습니다 (biplot.default의 코드 참조). 나는 이것이 매우 혼란 스럽다는 것을 알았습니다. – amoeba 3 월 19 일 15시 10:06
2. biplot()
점수 플롯을 플롯하고 동시에 화살표를 표시합니다.
축은 첫 번째 플롯에 해당하는 단위 제곱의 합계로 조정됩니다 @amoeba의 post 에서 첫 번째 행의 첫 에 . 이는 svd 분해 의 행렬 (이후에 더 자세히 설명 됨)를 플로팅하여 재현 할 수 있습니다 - " 열 : 이것들은 단위 제곱의 합으로 스케일링 된 주요 구성 요소입니다. "UUU
Biplot 구성의 하단 및 상단 가로 축에는 두 가지 스케일이 있습니다.
그러나 상대적인 규모는 즉시 명확하지 않으므로 기능과 방법을 탐구해야합니다.
biplot()
직교 단위 벡터 인 SVD에서 점수를 열로 표시합니다 .U
> scr.svd = svd(CEN)$u %*% diag(svd(CEN)$d)
> U = svd(CEN)$u
> apply(U, 2, function(x) sum(x^2))
[1] 1 1 1
prcomp()
R 의 함수는 고유 값으로 조정 된 점수를 반환합니다.
> apply(scr, 2, function(x) var(x)) # pr.comp() scores scaled to evals
PC1 PC2 PC3
2.02142986 0.90743458 0.07113557
> evals #... here is the proof:
[1] 2.02142986 0.90743458 0.07113557
따라서 고유 값으로 나누어 분산을 로 조정할 수 있습니다 .1
> scr_var_one = scr/sqrt(evals)[col(scr)] # to scale to var = 1
> apply(scr_var_one, 2, function(x) var(x)) # proved!
[1] 1 1 1
그러나 우리는 제곱의 합을 원하기 때문에 √1 하기 때문에 다음과 같은 이유로 로 나누어야합니다 .n−1−−−−−√
var(scr_var_one)=1=∑n1scr_var_onen−1
> scr_sum_sqrs_one = scr_var_one / sqrt(nrow(scr) - 1) # We / by sqrt n - 1.
> apply(scr_sum_sqrs_one, 2, function(x) sum(x^2)) #... proving it...
PC1 PC2 PC3
1 1 1
스케일링 팩터 의 사용은 나중에로 변경됩니다. √n−1−−−−−√n−−√lan
설명을 정의 할 때 된다는 사실에 유의하십시오.
prcomp
용도는 "princomp 달리, 분산은 통상적으로 계산되는 제수n − 1n−1n−1 ".
모든 그들을 제거 후 if
진술 및 기타 집안 청소 보풀을biplot()
다음과 같이 진행하십시오.
X = as.matrix(iris[,1:3]) # The original dataset
CEN = scale(X, center = T, scale = T) # Centered and scaled
PCA = prcomp(CEN) # PCA analysis
par(mfrow = c(1,2)) # Splitting the plot in 2.
biplot(PCA) # In-built biplot() R func.
# Following getAnywhere(biplot.prcomp):
choices = 1:2 # Selecting first two PC's
scale = 1 # Default
scores= PCA$x # The scores
lam = PCA$sdev[choices] # Sqrt e-vals (lambda) 2 PC's
n = nrow(scores) # no. rows scores
lam = lam * sqrt(n) # See below.
# at this point the following is called...
# biplot.default(t(t(scores[,choices]) / lam),
# t(t(x$rotation[,choices]) * lam))
# Following from now on getAnywhere(biplot.default):
x = t(t(scores[,choices]) / lam) # scaled scores
# "Scores that you get out of prcomp are scaled to have variance equal to
# the eigenvalue. So dividing by the sq root of the eigenvalue (lam in
# biplot) will scale them to unit variance. But if you want unit sum of
# squares, instead of unit variance, you need to scale by sqrt(n)" (see comments).
# > colSums(x^2)
# PC1 PC2
# 0.9933333 0.9933333 # It turns out that the it's scaled to sqrt(n/(n-1)),
# ...rather than 1 (?) - 0.9933333=149/150
y = t(t(PCA$rotation[,choices]) * lam) # scaled eigenvecs (loadings)
n = nrow(x) # Same as dataset (150)
p = nrow(y) # Three var -> 3 rows
# Names for the plotting:
xlabs = 1L:n
xlabs = as.character(xlabs) # no. from 1 to 150
dimnames(x) = list(xlabs, dimnames(x)[[2L]]) # no's and PC1 / PC2
ylabs = dimnames(y)[[1L]] # Iris species
ylabs = as.character(ylabs)
dimnames(y) <- list(ylabs, dimnames(y)[[2L]]) # Species and PC1/PC2
# Function to get the range:
unsigned.range = function(x) c(-abs(min(x, na.rm = TRUE)),
abs(max(x, na.rm = TRUE)))
rangx1 = unsigned.range(x[, 1L]) # Range first col x
# -0.1418269 0.1731236
rangx2 = unsigned.range(x[, 2L]) # Range second col x
# -0.2330564 0.2255037
rangy1 = unsigned.range(y[, 1L]) # Range 1st scaled evec
# -6.288626 11.986589
rangy2 = unsigned.range(y[, 2L]) # Range 2nd scaled evec
# -10.4776155 0.8761695
(xlim = ylim = rangx1 = rangx2 = range(rangx1, rangx2))
# range(rangx1, rangx2) = -0.2330564 0.2255037
# And the critical value is the maximum of the ratios of ranges of
# scaled e-vectors / scaled scores:
(ratio = max(rangy1/rangx1, rangy2/rangx2))
# rangy1/rangx1 = 26.98328 53.15472
# rangy2/rangx2 = 44.957418 3.885388
# ratio = 53.15472
par(pty = "s") # Calling a square plot
# Plotting a box with x and y limits -0.2330564 0.2255037
# for the scaled scores:
plot(x, type = "n", xlim = xlim, ylim = ylim) # No points
# Filling in the points as no's and the PC1 and PC2 labels:
text(x, xlabs)
par(new = TRUE) # Avoids plotting what follows separately
# Setting now x and y limits for the arrows:
(xlim = xlim * ratio) # We multiply the original limits x ratio
# -16.13617 15.61324
(ylim = ylim * ratio) # ... for both the x and y axis
# -16.13617 15.61324
# The following doesn't change the plot intially...
plot(y, axes = FALSE, type = "n",
xlim = xlim,
ylim = ylim, xlab = "", ylab = "")
# ... but it does now by plotting the ticks and new limits...
# ... along the top margin (3) and the right margin (4)
axis(3); axis(4)
text(y, labels = ylabs, col = 2) # This just prints the species
arrow.len = 0.1 # Length of the arrows about to plot.
# The scaled e-vecs are further reduced to 80% of their value
arrows(0, 0, y[, 1L] * 0.8, y[, 2L] * 0.8,
length = arrow.len, col = 2)
예상대로 다음 biplot()
과 같이 직접 호출 된 출력을 재현합니다 (아래 이미지).biplot(PCA)
모든 미적 결함에서 (아래 왼쪽 그림)으로 .
가볼만한 곳:
- 화살표는 2 개의 주요 성분 중 각각의 하나의 스케일링 된 고유 벡터와 각각의 스케일링 된 스코어 (the
ratio
) 사이의 최대 비율과 관련된 스케일로 플롯된다 . AS @amoeba 의견 :
산점도 및 "화살표"는 화살표의 최대 (절대 값) x 또는 y 화살표 좌표가 산란 된 데이터 포인트의 최대 (절대 값) x 또는 y 좌표와 정확히 일치하도록 조정됩니다.
- 위에서 예상 한 바와 같이 점수 는 SVD 의 행렬 에 점수로 직접 표시 될 수 있습니다 .U