После отличного поста JD Long в этой теме я искал простой пример и код R, необходимый для создания PCA, а затем вернулся к исходным данным. Это дало мне некоторую непосредственную геометрическую интуицию, и я хочу поделиться тем, что я получил. Набор данных и код можно напрямую скопировать и вставить в R-форму Github .
Я использовал набор данных, который я нашел в Интернете по полупроводникам здесь , и я обрезал его до двух измерений - «атомный номер» и «точка плавления» - для облегчения построения графиков.
В качестве предостережения идея является чисто иллюстративной для вычислительного процесса: PCA используется для сокращения более чем двух переменных до нескольких производных главных компонентов или для определения коллинеарности также в случае нескольких функций. Так что это не нашло бы большого применения в случае двух переменных, и не было бы необходимости вычислять собственные векторы матриц корреляции, как указано @amoeba.
Далее, я сократил наблюдения с 44 до 15, чтобы облегчить задачу отслеживания отдельных точек. Конечным результатом стал каркас данных ( dat1
):
compounds atomic.no melting.point
AIN 10 498.0
AIP 14 625.0
AIAs 23 1011.5
... ... ...
Столбец «Соединения» указывает химическое строение полупроводника и играет роль названия строки.
Это может быть воспроизведено следующим образом (готово для копирования и вставки на консоли R):
dat <- read.csv(url("http://rinterested.github.io/datasets/semiconductors"))
colnames(dat)[2] <- "atomic.no"
dat1 <- subset(dat[1:15,1:3])
row.names(dat1) <- dat1$compounds
dat1 <- dat1[,-1]
Затем данные были масштабированы:
X <- apply(dat1, 2, function(x) (x - mean(x)) / sd(x))
# This centers data points around the mean and standardizes by dividing by SD.
# It is the equivalent to `X <- scale(dat1, center = T, scale = T)`
Далее следуют шаги линейной алгебры:
C <- cov(X) # Covariance matrix (centered data)
⎡⎣⎢at_nomelt_pat_no10,296melt_p0,2961⎤⎦⎥
Функция корреляции cor(dat1)
дает те же выходные данные для немасштабированных данных, что и функция cov(X)
для масштабированных данных.
lambda <- eigen(C)$values # Eigenvalues
lambda_matrix <- diag(2)*eigen(C)$values # Eigenvalues matrix
⎡⎣⎢λPC11.2964220λPC200.7035783⎤⎦⎥
e_vectors <- eigen(C)$vectors # Eigenvectors
12√⎡⎣⎢PC111PC21- 1⎤⎦⎥
∼ [ - 0,7 , - 0,7 ][ 0,7 , 0,7 ]
e_vectors[,1] = - e_vectors[,1]; colnames(e_vectors) <- c("PC1","PC2")
1.29642170.703578364,8 %eigen(C)$values[1]/sum(eigen(C)$values) * 100
∼ 65 %35,2 %
Мы включим оба собственных вектора, учитывая небольшой размер этого примера игрушечного набора данных, понимая, что исключение одного из собственных векторов приведет к уменьшению размерности - идея PCA.
Оценка матрица была определена в качестве матрицы умножения масштабированных данных ( X
) с помощью матрицы собственных векторов (или «вращений») :
score_matrix <- X %*% e_vectors
# Identical to the often found operation: t(t(e_vectors) %*% t(X))
X
[ 0,7 , 0,7 ]TПК1[ 0,7 , - 0,7 ]TПК2
[ 0,7 , - 0,7 ]
1
> apply(e_vectors, 2, function(x) sum(x^2))
PC1 PC2
1 1
тогда как ( нагрузки ) являются собственными векторами, масштабированными по собственным значениям (несмотря на запутанную терминологию во встроенных R-функциях, показанных ниже). Следовательно, нагрузки могут быть рассчитаны как:
> e_vectors %*% lambda_matrix
[,1] [,2]
[1,] 0.9167086 0.497505
[2,] 0.9167086 -0.497505
> prcomp(X)$rotation %*% diag(princomp(covmat = C)$sd^2)
[,1] [,2]
atomic.no 0.9167086 0.497505
melting.point 0.9167086 -0.497505
Интересно отметить, что повернутое облако данных (график оценки) будет иметь дисперсию по каждому компоненту (ПК), равную собственным значениям:
> apply(score_matrix, 2, function(x) var(x))
PC1 PC2
53829.7896 110.8414
> lambda
[1] 53829.7896 110.8414
Используя встроенные функции, результаты могут быть воспроизведены:
# For the SCORE MATRIX:
prcomp(X)$x
# or...
princomp(X)$scores # The signs of the PC 1 column will be reversed.
# and for EIGENVECTOR MATRIX:
prcomp(X)$rotation
# or...
princomp(X)$loadings
# and for EIGENVALUES:
prcomp(X)$sdev^2
# or...
princomp(covmat = C)$sd^2
U Σ VT) метод может быть применен для расчета PCA вручную; на самом деле, это метод, используемый в prcomp()
. Шаги могут быть прописаны как:
svd_scaled_dat <-svd(scale(dat1))
eigen_vectors <- svd_scaled_dat$v
eigen_values <- (svd_scaled_dat$d/sqrt(nrow(dat1) - 1))^2
scores<-scale(dat1) %*% eigen_vectors
Результат показан ниже, во-первых, расстояния от отдельных точек до первого собственного вектора, а на втором графике - ортогональные расстояния до второго собственного вектора:
Если бы вместо этого мы построили значения матрицы оценок (ПК1 и ПК2) - больше не «точки плавления» и «atomic.no», а действительно изменение базиса координат точки с собственными векторами в качестве основы, эти расстояния были бы сохраняется, но естественно становится перпендикулярным оси XY:
Хитрость была теперь в том, чтобы восстановить исходные данные . Точки были преобразованы путем простого умножения матрицы на собственные векторы. Теперь данные были повернуты обратно путем умножения на обратную матрицу собственных векторов с результирующим заметным изменением местоположения точек данных. Например, обратите внимание на изменение розовой точки «GaN» в левом верхнем квадранте (черный кружок на левом графике внизу), возвращаясь к своей начальной позиции в левом нижнем квадранте (черный кружок на правом графике внизу).
Теперь мы наконец восстановили исходные данные в этой «развернутой» матрице:
Помимо изменения координат вращения данных в PCA, результаты должны интерпретироваться, и этот процесс имеет тенденцию включать a biplot
, на котором точки данных наносятся на график относительно координат нового собственного вектора, и исходные переменные теперь накладываются как векторы. Интересно отметить эквивалентность положения точек между графиками во втором ряду приведенных выше графиков вращения («Счета с осью xy = собственные векторы») (слева на следующих графиках) и biplot
(к правильно):
Наложение исходных переменных в виде красных стрелок открывает путь для интерпретации PC1
вектора в направлении (или с положительной корреляцией) с обоими atomic no
и melting point
; и PC2
в качестве компонента вдоль растущих значений, atomic no
но отрицательно коррелированных с melting point
, соответствующих значениям собственных векторов:
PCA$rotation
PC1 PC2
atomic.no 0.7071068 0.7071068
melting.point 0.7071068 -0.7071068
Это интерактивное руководство Виктора Пауэлла дает немедленную обратную связь об изменениях собственных векторов при изменении облака данных.