Mũi tên của các biến cơ bản trong biplot PCA trong R


11

Có nguy cơ làm cho câu hỏi trở nên cụ thể bằng phần mềm và với lý do có tính phổ biến và đặc trưng của nó, tôi muốn hỏi về chức năng biplot()trong R, và cụ thể hơn là về cách tính và vẽ đồ thị của mũi tên đỏ được đặt chồng lên nhau, tương ứng đến các biến cơ bản.


[Để hiểu ý nghĩa của một số ý kiến, các lô ban đầu được đăng có một vấn đề đáng lo ngại về sự quan tâm khan hiếm, và hiện đã bị xóa.]


Tôi không thể hiểu làm thế nào bạn thực sự có mũi tên màu xanh lá cây của bạn. Họ không đúng. Thực tế là màu xanh lá cây s.length là khoảng. dài hơn hai lần so với màu xanh lá cây s. thong cho phép nghi ngờ bạn đang vẽ các vectơ liên quan đến các biến không được tiêu chuẩn hóa. Điều đó không thể xảy ra trên một nhóm PCA dựa trên các mối tương quan.
ttnphns

Mũi tên đỏ có vẻ đúng. Xem: chúng có cùng độ dài và đối xứng về PC2. Đó là vị trí khả dĩ duy nhất khi bạn làm PCA chỉ với 2 biến và dựa trên các mối tương quan (tức là các biến được tiêu chuẩn hóa). Trong PCA dựa trên mối tương quan, tải trọng (sự phối hợp của các mũi tên) là mối tương quan giữa PC và các biến. Trong ví dụ của bạn, các phần tải là (vars by PC) : .74752, .66424; -.74752, .66424.
ttnphns

@ttnphns Vâng, mũi tên màu đỏ là những gì tôi đang cố gắng sao chép (chúng là chính xác) và chúng được vẽ trong R với biplot(name_of_the_PCA)cuộc gọi, trong trường hợp này là biplot(PCA). Tôi đã tập trung và thu nhỏ dữ liệu.
Antoni Parellada

Vì vậy, câu hỏi của bạn là gì? Làm thế nào để tính tọa độ cho các mũi tên màu đỏ? Chúng phải là tải PCA . Đôi khi, các hàm riêng được vẽ (lệnh R của bạn có thể đã làm điều đó ??), tuy nhiên, cách đồng thuận, có ý nghĩa là vẽ đồ thị .
ttnphns

@ttnphns Vẽ đồ thị cho người bản địa (tôi cho rằng nó giống như tải trọng) cho tôi định hướng đúng (cảm ơn bạn), nhưng không phải là độ lớn như mũi tên màu đỏ (Tôi đang dán hình ảnh trong OP).
Antoni Parellada

Câu trả lời:


19

Xem xét nâng cấp bài đăng của @ amoeba@ttnphns . Cảm ơn cả hai vì sự giúp đỡ và ý tưởng của bạn.


Các mục sau đây dựa trên tập dữ liệu Iris trong R và cụ thể là ba biến (cột) đầu tiên : Sepal.Length, Sepal.Width, Petal.Length.

Một biplot kết hợp một biểu đồ tải (các hàm riêng không chuẩn) - trong bê tông, hai lần tải đầu tiên và một biểu đồ điểm (các điểm dữ liệu được xoay và giãn được vẽ theo các thành phần chính). Sử dụng cùng một tập dữ liệu, @amoeba mô tả 9 tổ hợp biplot PCA có thể dựa trên 3 chuẩn hóa có thể có của biểu đồ điểm số của các thành phần chính thứ nhất và thứ hai và 3 chuẩn hóa của biểu đồ tải (mũi tên) của các biến ban đầu. Để xem R xử lý các kết hợp có thể này như thế nào, thật thú vị khi xem biplot()phương thức:


Đầu tiên đại số tuyến tính đã sẵn sàng để sao chép và dán:

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. Tái tạo âm mưu tải (mũi tên):

Ở đây giải thích hình học trên bài đăng này của @ttnphns giúp rất nhiều. Ký hiệu của sơ đồ trong bài đã được duy trì: là viết tắt của biến trong không gian chủ đề . là mũi tên tương ứng cuối cùng được vẽ; và tọa độ và là tải phần một biến đối với với và :h a 1 a 2 V PC 1 PC 2VSepal L.ha1a2VPC1PC2


nhập mô tả hình ảnh ở đây


Thành phần của biến Sepal L.liên quan đến sau đó sẽ là:PC1

a1=hcos(ϕ)

trong đó, nếu điểm số liên quan đến - hãy gọi chúng là - được chuẩn hóa sao choS 1PC1S1

S1=1nscores12=1 , phương trình trên tương đương với sản phẩm chấm :VS1

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

Vì ,V=x2

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

Tương tự như vậy,

S1=1=var(S1)n1.

Quay trở lại phương trình. ,(1)

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

cos(ϕ)Do đó, có thể được coi là hệ số tương quan của Pearson , , với lời cảnh báo mà tôi không hiểu về nếp nhăn của yếu tố .rn1

Sao chép và chồng chéo trong màu xanh mũi tên màu đỏ của 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)

nhập mô tả hình ảnh ở đây

Điểm quan tâm:

  • Các mũi tên có thể được sao chép dưới dạng tương quan của các biến ban đầu với điểm số được tạo bởi hai thành phần chính đầu tiên.
  • Ngoài ra, điều này có thể đạt được như trong âm mưu đầu tiên ở hàng thứ hai, được gắn nhãn trong bài đăng của @ amoeba:VS

nhập mô tả hình ảnh ở đây

hoặc trong mã 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)

hoặc thậm chí ...

    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)

kết nối với giải thích hình học của tải trọng bởi @ttnphns hoặc bài đăng thông tin khác này cũng bởi @ttnphns .

  • Có một yếu tố tỷ lệ : sqrt(nrow(X) - 1), vẫn còn một chút bí ẩn.

  • 0.8 phải làm với việc tạo không gian cho nhãn - xem nhận xét này tại đây :

Ngoài ra, người ta nên nói rằng các mũi tên được vẽ sao cho trung tâm của nhãn văn bản là nơi cần có! Các mũi tên sau đó được nhân với 0,80,8 trước khi vẽ, tức là tất cả các mũi tên ngắn hơn so với những gì chúng cần, có lẽ là để ngăn chặn sự chồng chéo với nhãn văn bản (xem mã cho biplot.default). Tôi thấy điều này là vô cùng khó hiểu. - amip 19/03/2015 lúc 10:06


2. Vẽ sơ đồ biplot()điểm số (và mũi tên đồng thời):

Các trục được chia tỷ lệ thành đơn vị tổng bình phương, tương ứng với ô đầu tiên của hàng đầu tiên trên bài đăng của @ amoeba , có thể được sao chép âm mưu ma trận của phân tách svd (nhiều hơn về sau này) - " Cột của : đây là những thành phần chính được chia tỷ lệ thành đơn vị tổng bình phương. "UU

nhập mô tả hình ảnh ở đây

Có hai thang đo khác nhau khi chơi trên các trục ngang dưới và trên cùng trong cấu trúc biplot:

nhập mô tả hình ảnh ở đây

Tuy nhiên, quy mô tương đối không rõ ràng ngay lập tức, đòi hỏi phải đi sâu vào các chức năng và phương thức:

biplot()vẽ đồ thị điểm như các cột của trong SVD, là các vectơ đơn vị trực giao: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

Trong khi đó prcomp()hàm trong R trả về điểm số được chia tỷ lệ theo giá trị riêng của chúng:

> 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

Do đó, chúng ta có thể chia tỷ lệ phương sai thành bằng cách chia cho các giá trị riêng: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

Nhưng vì chúng tôi muốn tổng bình phương là , chúng tôi sẽ cần chia cho vì:1n1

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

Lưu ý rằng việc sử dụng hệ số tỷ lệ , sau này được thay đổi thành khi xác định giải thích dường như nằm trong thực tế rằngn1nlan

prcompsử dụng : "Không giống như Princeomp, phương sai được tính với ước số thông thường ".n1n1


Sau khi tước bỏ tất cả các iftuyên bố và lông tơ khác, biplot()tiến hành như sau:

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)

mà, như mong đợi, tái tạo (hình bên phải bên dưới) biplot()đầu ra như được gọi trực tiếp với biplot(PCA)(âm mưu bên trái bên dưới) trong tất cả các thiếu sót thẩm mỹ chưa được xử lý của nó:

nhập mô tả hình ảnh ở đây

Điểm quan tâm:

  • Các mũi tên được vẽ ở một tỷ lệ liên quan đến tỷ lệ tối đa giữa trình xác định tỷ lệ của mỗi một trong hai thành phần chính và điểm số tỷ lệ tương ứng của chúng (the ratio). NHƯ bình luận @amoeba:

biểu đồ phân tán và "biểu đồ mũi tên" được chia tỷ lệ sao cho tọa độ mũi tên x hoặc y lớn nhất (về giá trị tuyệt đối) của mũi tên chính xác bằng tọa độ x (y tuyệt đối) lớn nhất của các điểm dữ liệu phân tán

  • Như đã dự đoán ở trên, các điểm có thể được vẽ trực tiếp dưới dạng điểm trong ma trận của SVD:U


1
+1, Học giỏi. Tôi đã thêm thẻ Rvào câu hỏi của bạn vì vấn đề khó hiểu (cụ thể là hệ số tỷ lệ) đã được chứng minh là một phần cụ thể R. Nói chung, bạn có thể thấy rằng biplot PCA là một biểu đồ phân tán lớp phủ của điểm thành phần (tọa độ hàng) và hệ số hướng thành phần (tọa độ cột) và do nhiều mức độ tiêu chuẩn hóa theo "quán tính" (phương sai) có thể được áp dụng cho từng loại của quá, vì vậy các hình thức khác nhau của biplot có thể phát sinh. Để thêm: điển hình nhất (ý nghĩa hơn), tải được hiển thị dưới dạng tọa độ cột (mũi tên).
ttnphns

1
(tt) Xem tổng quan của tôi về biplot giải thích, nói cách khác, những gì bạn đã thể hiện trong câu trả lời hay của bạn.
ttnphns

2
+ 1 cảm ơn vì đã viết hướng dẫn và với mã tái sản xuất cho chúng tôi!
Haitao Du

Antony, bạn đã vẽ (bằng tay) hay bạn đã vẽ (được cung cấp dữ liệu) pic của bạn? Bạn đã sử dụng phần mềm nào? Trông thật tuyệt
ttnphns

@ttnphns Cảm ơn bạn! Đây là liên kết đến nó . Tôi đã tự hỏi nếu bạn có thể cải thiện nó, và vẽ đồ thị và PC theo cách tốt hơn, mô phạm hơn. Hãy thoải mái thay đổi (đây là một chương trình thân thiện với người dùng tuyệt vời) và nếu bạn muốn, hãy chia sẻ.
Antoni Parellada
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.