Розгляньте питання про звернення до @ amoeba та @ttnphns . Дякую вам і за допомогу, і за ідеї.
Нижче спирається на набір даних Iris в R , і , в зокрема, перші три змінні (стовпці): Sepal.Length, Sepal.Width, Petal.Length
.
Biplot поєднує в собі завантажувальний ділянку (нестандартизованого власні вектори) - в бетоні, перші дві навантажень , і оцінку ділянку (повернені і розширені точки даних , побудовані по відношенню до основних компонентів). Використовуючи той самий набір даних, @amoeba описує 9 можливих комбінацій біплоту PCA на основі 3 можливих нормалізацій схеми оцінки першого та другого головних компонентів та 3 нормалізації графіку завантаження (стрілки) початкових змінних. Щоб побачити, як 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 ' - відповідна стрілка в кінцевому підсумку; а координати 1 і 2 є складовими навантаженнями змінної V по відношенню до ПК 1 і ПК 2 :VSepal L.
год'а1а2VПК 1ПК 2
Складовою змінної Sepal L.
стосовно буде:ПК 1
а1= h ⋅ cos( ϕ )
ПК 1S 1
∥ S 1 ∥ = ∑н1балів21---------√= 1V⋅ S 1
а1=V⋅ S 1= ∥V∥∥ S 1∥cos( ϕ )= h × 1 × ⋅cos( ϕ )(1)
∥V∥ = ∑x2−---√
Вар ( V)-----√= ∑ x2----√n - 1-----√= ∥ V∥n - 1-----√⟹∥ V∥ = h = var ( V)-----√n - 1-----√.
Так само,
∥ S 1 ∥ = 1 = var (S 1 )-----√n - 1-----√.
( 1 )
а1= h × 1 × ⋅ cos( ϕ ) = var ( V)-----√var ( S 1 )-----√cos( θ )( n - 1 )
cos( ϕ )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)
Цікаві місця:
- Стрілки можуть бути відтворені у вигляді співвідношення вихідних змінних з балами, сформованими за першими двома основними компонентами.
- 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). Я вважаю це надзвичайно заплутаним. - амеба 19 березня 15 р. О 10:06
2. Складання графіків biplot()
балів (і стрілок одночасно):
UU
На нижній та верхній горизонтальних осях у конструкції біплоту є дві різні шкали:
Однак відносна шкала не відразу очевидна, що вимагає заглиблення у функції та методи:
biplot()
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
1n - 1-----√
var ( scr_var_one ) = 1 = ∑н1scr_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-----√н--√lan
prcomp
n - 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)
(лівий сюжет внизу), у всіх його недоторканих естетичних недоліках:
Цікаві місця:
- Стрілки побудовані в масштабі, пов'язаному з максимальним співвідношенням між масштабованим власним вектором кожного з двох основних компонентів та їх відповідними масштабними балами (the
ratio
). AS @amoeba коментарі:
графік розсіювання та "графік стрілки" масштабуються таким чином, що найбільша (в абсолютній величині) х або у координатна стрілка стрілок була точно рівною найбільшій (в абсолютній величині) х або у координаті розсіяних точок даних