R에서 PCA biplot의 기본 변수 화살표


11

소프트웨어에 의문을 제기하고 편재와 특유성에 대한 변명으로 biplot()R 의 함수 에 대해 묻고 싶습니다 . 더 구체적으로, 중첩 된 기본 빨간색 화살표의 계산 및 플로팅에 대해 묻고 싶습니다. 기본 변수에.


[일부 의견을 이해하기 위해, 처음 게시 된 음모에는 관심이 거의없는 문제가 있었으며 이제 지워졌습니다.]


초록색 화살표를 실제로 어떻게 얻었는지 알 수 없습니다. 그들은 정확하지 않습니다. s.length 녹색이 대략적인 사실. s.width 녹색보다 두 배 더 길면 표준화되지 않은 변수와 관련된 벡터를 플로팅 한 것으로 의심 할 수 있습니다. 상관 관계를 기반으로하는 PCA의 이중 플롯에서는 발생할 수 없습니다.
ttnphns

빨간색 화살표가 올바른 것 같습니다. 참조 : 길이는 동일하며 PC2에 대해 대칭입니다. 이는 단지 2 개의 변수로 상관 관계 (예 : 표준화 된 변수)를 기반으로 PCA를 수행 할 때 가능한 유일한 위치입니다. 상관 관계에 기반한 PCA에서 로딩 (화살표의 좌표)은 PC와 변수 사이의 상관 관계입니다. 귀하의 예에서, 로딩 량은 (PC에 따라 다름) : .74752, .66424; -.74752, .66424입니다.
ttnphns

@ttnphns 그렇습니다. 빨간색 화살표는 내가 재현하려고하는 것입니다 (정확합니다) . biplot(name_of_the_PCA)이 경우 R은 호출 과 함께 플롯됩니다 biplot(PCA). 나는 데이터를 중심에두고 확장했다.
Antoni Parellada

그래서, 당신의 질문은 무엇입니까? 빨간색 화살표의 좌표를 계산하는 방법은 무엇입니까? 이것은 PCA 로딩 이어야합니다 . 때때로, 고유 벡터가 그려 지지만 (R 명령이 아마도 그렇게했을까요?) 합의적이고 의미있는 방법 은 하중을 플롯하는 것 입니다.
ttnphns

@ttnphns 고유 벡터를 플로팅하면 (로드와 동일하다고 가정) 올바른 방향 (감사합니다)을 제공하지만 빨간색 화살표와 같은 크기는 아닙니다 (OP에 이미지를 붙여 넣습니다).
Antoni Parellada

답변:


19

@ amoeba 's@ttnphns 'post 업 보팅을 고려하십시오 . 당신의 도움과 아이디어에 감사드립니다.


다음은 RIris 데이터 세트 , 특히 처음 세 변수 (열) 에 의존합니다 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 1a 2PC 1PC 2에 대한 변수 V 를 로드하는 구성 요소입니다 .VSepal L.ha1a2VPC1PC2


여기에 이미지 설명을 입력하십시오


PC 1에Sepal L. 대한 변수의 구성 요소 는 다음과 같습니다.PC1

a1=hcos(ϕ)

이는의 경우 점수 에 대한 -하자 그들을 호출 S 1 - 그래서 표준화되어 자신의PC1S1

VS1S1=1nscores12=1VS1

a1=VS1=VS1cos(ϕ)(1)=h×1×cos(ϕ)

이후 ,V=x2

Var(V)=x2n1=Vn1V=h=var(V)n1.

마찬가지로,

S1=1=var(S1)n1.

방정식으로 돌아 가기 ,(1)

a1=h×1×cos(ϕ)=var(V)var(S1)cos(θ)(n1)

r n - 1cos(ϕ) , 따라서 고려 될 수있는 피어슨 상관 계수 , , I는의 주름 이해하지 못하고 있다는 경고와 인자.rn1

빨간색 화살표가 파란색으로 중복되고 겹칩니다. 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의 게시물에 로 표시된 두 번째 행의 첫 번째 플롯에서와 같이 얻을 수 있습니다 .VS

여기에 이미지 설명을 입력하십시오

또는 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의 다른 정보 게시물에 대한 기하학적 설명 과 연결 .

  • 스케일링 팩터가 있습니다 : sqrt(nrow(X) - 1)약간의 미스터리로 남아 있습니다.

  • 0.8 은 레이블을위한 공간을 만드는 것과 관련이 있습니다. 여기 에서이 주석을 보십시오 :

또한 텍스트 레이블의 중심이 있어야 할 곳에 화살표가 그려져 있어야합니다! 그런 다음 플로팅하기 전에 화살표에 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 하기 때문에 다음과 같은 이유로 로 나누어야합니다 .n1

var(scr_var_one)=1=1nscr_var_onen1
> 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

스케일링 팩터 의 사용은 나중에로 변경됩니다.n1nlan 설명을 정의 할 때 된다는 사실에 유의하십시오.

prcomp용도는 "princomp 달리, 분산은 통상적으로 계산되는 제수n 1n1n1 ".


모든 그들을 제거 후 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


1
+1, 좋은 공부. R혼란스러운 물질 (즉, 스케일링 계수)이 부분적으로 R에 특정한 것으로 판명되어 귀하의 질문 에 태그 를 추가했습니다 . 일반적으로 PCA biplot은 구성 요소 점수 (행 좌표) 및 구성 요소 방향 계수 (열 좌표)의 오버레이 산점도이며 "관성"(분산)에 의한 다양한 양의 od 표준화가 각각에 적용될 수 있기 때문에 Biplot의 다양한 모양이 발생할 수 있습니다. 추가 : 가장 일반적으로 (더 의미있는) 하중 은 열 좌표 (화살표)로 표시됩니다.
ttnphns

1
(계속) Biplot에 대한 나의 개요를 보시면 여러분이 멋진 답변에 보여준 것을 다른 말로 설명합니다.
ttnphns

2
+ 1 자습서를 작성하고 재현 가능한 코드를 제공해 주셔서 감사합니다!
Haitao Du

안토니, 손으로 그림을 그리거나 그림으로 그림을 그리셨습니까? 어떤 소프트웨어를 사용하셨습니까? 보기 좋네요.
ttnphns 2016 년

@ttnphns 감사합니다! 여기에 링크가 있습니다 . 나는 당신이 그것을 향상시킬 수 있는지 궁금해하고 로딩과 PC를 더 좋고 교훈적인 방식으로 플롯합니다. 자유롭게 변경하십시오 (놀랍게도 사용자 친화적 인 프로그램입니다). 그렇다면 공유하십시오.
Antoni Parellada
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.