Setelah posting yang sangat baik oleh JD Long di utas ini, saya mencari contoh sederhana, dan kode R diperlukan untuk menghasilkan PCA dan kemudian kembali ke data asli. Itu memberi saya beberapa intuisi geometri tangan pertama, dan saya ingin berbagi apa yang saya dapatkan. Dataset dan kode dapat secara langsung disalin dan ditempelkan ke R form Github .
Saya menggunakan kumpulan data yang saya temukan online pada semikonduktor di sini , dan saya memangkasnya menjadi hanya dua dimensi - "nomor atom" dan "titik lebur" - untuk memfasilitasi perencanaan.
Sebagai peringatan, idenya murni menggambarkan proses komputasi: PCA digunakan untuk mengurangi lebih dari dua variabel menjadi beberapa komponen utama turunan, atau untuk mengidentifikasi collinearity juga dalam kasus beberapa fitur. Jadi itu tidak akan menemukan banyak aplikasi dalam kasus dua variabel, juga tidak akan ada kebutuhan untuk menghitung vektor eigen dari matriks korelasi seperti yang ditunjukkan oleh @amoeba.
Selanjutnya, saya memotong pengamatan dari 44 menjadi 15 untuk memudahkan tugas melacak setiap poin. Hasil akhirnya adalah kerangka data kerangka ( dat1
):
compounds atomic.no melting.point
AIN 10 498.0
AIP 14 625.0
AIAs 23 1011.5
... ... ...
Kolom "senyawa" menunjukkan konstitusi kimia semikonduktor, dan memainkan peran nama baris.
Ini dapat direproduksi sebagai berikut (siap untuk menyalin dan menempel pada konsol 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]
Data kemudian diskalakan:
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)`
Langkah-langkah aljabar linier mengikuti:
C <- cov(X) # Covariance matrix (centered data)
⎡⎣⎢at_nomelt_pat_no10,296melt_p0,2961⎤⎦⎥
Fungsi korelasi cor(dat1)
memberikan output yang sama pada data non-skala dengan fungsi cov(X)
pada data yang diskalakan.
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⎤⎦⎥
Karena vektor eigen pertama awalnya kembali sebagai ∼ [ - 0,7 , - 0,7 ] kami memilih untuk mengubahnya [ 0,7 , 0,7 ] untuk membuatnya konsisten dengan formula bawaan melalui:
e_vectors[,1] = - e_vectors[,1]; colnames(e_vectors) <- c("PC1","PC2")
Nilai eigen yang dihasilkan adalah 1.2964217 dan 0,7035783. Dalam kondisi yang kurang minimalis, hasil ini akan membantu memutuskan vektor eigen mana yang akan dimasukkan (nilai eigen terbesar). Misalnya, kontribusi relatif dari nilai eigen pertama adalah64,8 %: eigen(C)$values[1]/sum(eigen(C)$values) * 100
, artinya akun itu∼ 65 %dari variabilitas dalam data. Variabilitas dalam arah vektor eigen kedua adalah35,2 %. Ini biasanya ditunjukkan pada plot scree yang menggambarkan nilai nilai eigen:
Kami akan menyertakan kedua vektor eigen mengingat ukuran kecil dari kumpulan data mainan ini, memahami bahwa mengecualikan salah satu vektor eigen akan menghasilkan pengurangan dimensi - ide di balik PCA.
The matriks skor ditentukan sebagai perkalian matriks dari data yang skala ( X
) dengan matriks vektor eigen (atau "rotasi") :
score_matrix <- X %*% e_vectors
# Identical to the often found operation: t(t(e_vectors) %*% t(X))
Konsep ini memerlukan kombinasi linier dari setiap entri (baris / subjek / pengamatan / superkonduktor dalam kasus ini) dari data terpusat (dan dalam kasus ini diskalakan) ditimbang oleh baris masing-masing vektor eigen , sehingga di setiap kolom akhir dari skor matrix, kita akan menemukan kontribusi dari setiap variabel (kolom) dari data (keseluruhan X
), TAPI hanya vektor eigen yang sesuai yang akan mengambil bagian dalam perhitungan (yaitu vektor eigen pertama[ 0.7, 0,7 ]T akan berkontribusi PC1 (Komponen Utama 1) dan [ 0,7 , - 0,7 ]T untuk PC2, seperti dalam:
Oleh karena itu setiap vektor eigen akan mempengaruhi masing-masing variabel secara berbeda, dan ini akan tercermin dalam "pemuatan" PCA. Dalam kasus kami, tanda negatif pada komponen kedua vektor eigen kedua[ 0,7 , - 0,7 ] akan mengubah tanda nilai titik lebur dalam kombinasi linear yang menghasilkan PC2, sedangkan efek vektor eigen pertama akan secara konsisten positif:
Vektor eigen diskalakan ke 1:
> apply(e_vectors, 2, function(x) sum(x^2))
PC1 PC2
1 1
sedangkan ( memuat ) adalah vektor eigen yang diskalakan oleh nilai eigen (meskipun ada terminologi yang membingungkan dalam fungsi R built-in yang ditampilkan di bawah). Akibatnya, beban dapat dihitung sebagai:
> 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
Sangat menarik untuk dicatat bahwa cloud data yang diputar (plot skor) akan memiliki varian di sepanjang setiap komponen (PC) yang sama dengan nilai eigen:
> apply(score_matrix, 2, function(x) var(x))
PC1 PC2
53829.7896 110.8414
> lambda
[1] 53829.7896 110.8414
Memanfaatkan fungsi bawaan, hasilnya dapat direplikasi:
# 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
Atau, dekomposisi nilai singular (U Σ VT) metode dapat diterapkan untuk menghitung PCA secara manual; sebenarnya, ini adalah metode yang digunakan di prcomp()
. Langkah-langkahnya bisa dijabarkan sebagai:
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
Hasilnya ditunjukkan di bawah ini, dengan pertama, jarak dari masing-masing titik ke vektor eigen pertama, dan pada plot kedua, jarak ortogonal ke vektor eigen kedua:
Jika sebaliknya kita merencanakan nilai matriks skor (PC1 dan PC2) - tidak lagi "melting.point" dan "atomic.no", tetapi benar-benar perubahan basis titik yang dikoordinasikan dengan vektor eigen sebagai basis, jarak ini akan menjadi diawetkan, tetapi secara alami akan menjadi tegak lurus terhadap sumbu xy:
Caranya sekarang adalah memulihkan data asli . Poin telah ditransformasikan melalui perkalian matriks sederhana dengan vektor eigen. Sekarang data diputar kembali dengan mengalikannya dengan kebalikan dari matriks vektor eigen dengan perubahan ditandai yang dihasilkan di lokasi titik data. Misalnya, perhatikan perubahan titik merah muda "GaN" di kuadran kiri atas (lingkaran hitam di plot kiri, di bawah), kembali ke posisi awalnya di kuadran kiri bawah (lingkaran hitam di plot kanan, di bawah).
Sekarang kami akhirnya mengembalikan data asli ke dalam matriks "de-rotated" ini:
Di luar perubahan koordinat rotasi data dalam PCA, hasilnya harus ditafsirkan, dan proses ini cenderung melibatkan biplot
, di mana titik-titik data diplot sehubungan dengan koordinat vektor eigen baru, dan variabel asli sekarang ditumpangkan sebagai vektor. Sangat menarik untuk mencatat kesetaraan dalam posisi titik antara plot di baris kedua dari grafik rotasi di atas ("Skor dengan sumbu xy = vektor Eigen") (di sebelah kiri di plot yang mengikuti), dan biplot
(ke Baik):
Superimposisi variabel asli sebagai panah merah menawarkan jalur untuk interpretasi PC1
sebagai vektor dalam arah (atau dengan korelasi positif) dengan keduanya atomic no
dan melting point
; dan PC2
sebagai komponen sepanjang peningkatan nilai atomic no
tetapi berkorelasi negatif dengan melting point
, konsisten dengan nilai-nilai vektor eigen:
PCA$rotation
PC1 PC2
atomic.no 0.7071068 0.7071068
melting.point 0.7071068 -0.7071068
Tutorial interaktif oleh Victor Powell ini memberikan umpan balik segera mengenai perubahan vektor eigen saat awan data diubah.