Principal Components Analysis (PCA) ต่างจาก Factor Analysis (FA) ยังไง ??? (ตอนที่ 1)
ความรู้เบื้องต้นที่ใช้ในการทำ PCA กับ FA
- พื้นฐานสถิติ อย่างเช่น Variance , Covariance
- พื้นฐานเกี่ยวกับการคำนวณ Matrix
จริงๆทั้ง 2 วิธีเป็นเทคนิคในการทำ dimension reduction ประเภท Feature Extraction เหมือนกันทำให้เราได้ จำนวนตัวแปรใหม่ที่มีขนาดลดลง แต่สิ่งที่แตกต่างกัน คือ PCA เป็นการสร้าง component ใหม่ โดยการหา linear combination จากตัวแปรตั้งต้น เพื่ออธิบาย information ให้ได้มากที่สุด ส่วน FA เป็นการค้นหา latent factor (factor ที่ซ่อนเร้น) จากตัวแปรที่มีความสัมพันธ์ร่วมกัน (co-variance ระหว่าง ตัวแปร) พูดให้ฟังดูง่ายขึ้นก็คือจับตัวแปรที่มีความสัมพันธ์กันสูงๆให้อยู่ใน factor เดียวกันนั่นเอง เรามาดูในรายละเอียดของแต่ละตัวกันดีกว่าครับ
มาดู Principal Components Analysis (PCA) กันก่อน
จุดประสงค์ในการทำ PCA
- แก้ปัญหา high-dimensional data ข้อมูลที่มีจำนวนตัวแปร เยอะกว่าจำนวนตัวอย่าง (n น้อยกว่า p) จะเจอปัญหานี้เยอะในงานพวก image processing งานวิเคราะห์ทางการแพทย์ เช่น วิเคราะห์ Gene Expression ของผู้ป่วยโรคมะเร็ง
- เพื่อลดจำนวนของตัวแปรลง โดยที่ไม่อยากจะตัดตัวแปรที่เราได้ทิ้ง (ไม่อยากจะเสีย information) แต่อาจจะทำให้อธิบายหรือตีความผลการวิเคราะห์ได้ยากขึ้นหน่อยนึง
- ลดปัญหาตัวแปรมีความสัมพันธ์กัน (Multicollinearity) เพราะ component แต่ละตัวจะไม่มีความสัมพันธ์กัน
PCA จะทำการสร้างตัวแปรขึ้นมาใหม่เรียกว่า component โดยแต่ละ component จะไม่มีความสัมพันธ์กัน โดย component ตัวแรกจะมีค่า variance สูงที่สุด ซึ่งจะอธิบาย information ได้มากที่สุด และตัวถัดๆ ไปก็จะมี variance ลดหลั่นกันไปตามลำดับ โดยปกติจำนวน component ที่เหมาะสมที่ถูกเลือกมาใช้จะครอบคลุม variance ประมาณ 80–90%
แล้วทำไม variance ต่อ total population variance ของตัวแปรใหม่ (component) ยิ่งเยอะยิ่งให้ information เยอะ?
ผมจะลองยกตัวอย่างเพื่อให้เข้าใจได้ง่ายขึ้น สมมติ เราจะทำการศึกษาพฤติกรรมการซื้อสิ้นค้าของคน โดยสุ่มตัวอย่าง มาทำการวิเคราะห์ กรณีแรก เราศึกษาพฤติกรรมการซื้อสิ้นค้าจากตัวอย่างของคนที่มีเงินเดือนในช่วง 20,000 ถึง 30,000 บาท กับกรณีที่ 2 ศึกษาจากตัวอย่างของคนที่มีเงินเดือนในช่วงตั้งแต่ 5,000 ถึง 100,000 บาท ในกรณีแรกจะเห็นว่า variance ของตัวแปรเงินเดือนนั้นต่ำกว่ากรณีที่ 2 มาก ซึ่งในกรณีแรกเราอาจจะพบว่า การซื้อสินค้าของคนกลุ่มนี้ก็จะมีลักษณะคล้ายๆ กัน ส่วนกรณีที่ 2 จะได้พฤติกรรมการซื้อสินค้าที่หลากหลายกว่า ซึ่งก็คือ information ที่มีเยอะมากกว่านั่นเอง
ผมไม่ได้บอกว่าการมี variance เยอะจะดีเสมอไปนะครับ มันดีในกรณีของการทำ PCA เพราะเราต้องการสร้าง component ที่สามารถจะอธิบายข้อมูลได้มากๆ แต่ถ้า variance ดันมีอยู่เยอะในตัวแปรที่เราจะ predict ละก็ ผลการ predict ของเราก็จะมี error พุ่งปรี๊ดกันเลยที่เดียว
ถามว่าเราสนใจใช้เพียงแค่ variance ของตัวแปรในการวัดปริมาณของ information ที่เราจะได้ใช่มั้ย ?
ตอบเลยครับว่าไม่ใช่อย่างแน่นอน ลองนึกดูว่า สมมติเรามีตัวแปร 2 ตัว ทั้งคู่มี variance เยอะโคตรๆ แต่ตัวแปร 2 ตัวนี้คล้ายกันแบบสุดๆ Correlation เกือบจะเป็น 1 เรียกได้ว่าเหมือนกันอย่างกับแกะ ถ้ามันเป็นแบบนี้ information ที่เราจะได้จากตัวแปรทั้ง 2 ตัวจะต่างกับ ที่เราได้จากตัวเดียวมั้ย? เรียกได้ว่าอาจจะหาความแตกต่างของ information ไม่เจอ แสดงว่าใช้แค่ตัวแปรตัวแรกก็เพียงพอแล้ว เอาตัวแปรตัวที่ 2 เข้ามาก็ไม่ได้ให้ information อะไรเพิ่มขี้น
ดังนั้นการทำ PCA เพื่อสร้าง component ใหม่ขึ้นมานั้นเราไม่ได้ดูแค่เฉพาะ variance เท่านั้น เรายังต้องทำให้ component แต่ละ component ของเราไม่มีความสัมพันธ์กันด้วย (Co-variance Matrix ของ component จะเป็น Diagonal Matrix)
มาดูหลักการทางคณิตศาสตร์และสถิติกันบ้าง
การหา component จะหาได้จากสมการ Y=WX
Y คือ Matrix ของ component ขนาด p x 1
W คือ Matrix ค่าสัมประสิทธ์ของตัวแปร X ขนาด p x p และ
X ก็คือ Matrix ของตัวแปรตั้งต้น ขนาด p x 1
กระจายออกมาเป็น linear combination ได้รูปนี้
จากรูปนี้เราจะเห็นว่าการทำ PCA จะเป็นการสร้าง Component ใหม่ขึ้นมาโดยทำการรวม information ของ ตัวแปร X ทั้งหมดที่เรามีอยู่โดยไม่ได้ตัดตัวแปรทิ้งไปสักตัว ทำให้เราไม่เสีย information ไม่เหมือนกับการทำ Feature Selection หรือ Feature Elimination ที่เสีย information (ตัวแปร) ที่เราเก็บมาไปบางส่วน
เนื่องจากเราต้องการสร้าง component ใหม่ที่ไม่มีความสัมพันธ์กัน ตามทฤษฎี Diagonalization (https://en.wikipedia.org/wiki/Diagonalizable_matrix) บอกว่า Matrix ที่สมมาตร (Symmetry Matrix) สามารถเขียนให้อยู่ในรูปมการด้านล่าง ในกรณีของเราคือ Co-variance Matrix ของตัวแปร X (S มีขนาด p x p)
Matrix W จะเป็น Orthogonal Matrix ขนาด p x p
D เป็น Diagonal Matrix ขนาด pxp
Matrix D นี่แหละคือ Co-variance Matrix ของ component Cov(Y) = D
ตอนนี้เรายังไม่รู้ค่า P จากแต่สมการ S=WDWˉ¹ ลองย้ายข้างดูจะได้เป็น SWˉ¹=DWˉ¹ พบว่า Pˉ¹(หรือ Pᵀ ) มันก็คือ Eigenvector นั่นเอง (ใช้เป็นค่าสัมประสิทธ๋ของตัวแปร X แต่เวลาใช้ก็ transpose ก่อน เพราะในสมการมัน คือ Y=WX แต่ Eigenvector ที่เราได้มามันคือ Pᵀ) ส่วน D ก็เป็น Eigenvalue
พอเรารู้หลักการแล้ว เราก็มาลองทำกันเลยดีกว่า
ผมใช้ข้อมูลรูปหน้าคนมาลองทำ PCA ซึ่งข้อมูลเอามาจาก Kaggle ตามลิ๊งนี้เลยครับ
เริ่มแรกเราต้องทำการอ่าน data ที่เราจะวิเคราะห์
file <- “D:/Ingenio/Dataset/training/facetraining.csv”
pictures <- read.csv(file)# ผมจะใช้แค่ 100 รูปในการทำ PCA
data = pictures[1:100,]
im.train <- as.character(data$Image)library(doParallel)
registerDoParallel(cores=4)
im.train <- foreach(im = im.train, .combine=rbind) %dopar% {
as.integer(unlist(strsplit(im, " ")))
}# แสดงผลข้อมูล
options(repr.plot.width=8, repr.plot.height=2)
par(mfrow=c(2,8),mar=c(0,0,0,0) )
for(i in 1:16){
im2 <- matrix(data=rev(im.train[i,]), nrow=96, ncol=96)
plot2 <- image(1:96, 1:96, im2, col=gray((0:255)/255),xaxt='n'
,yaxt='n', ann=FALSE)
}
X <- t(t(im.train))
แล้วทำการหา Co-variance (หรือจะหา Correlation) ของตัวแปร X กันก่อน เพื่อดูความคล้ายคลึงกันของตัวแปร กรณีที่จะใช้ Co-variance ตัวแปรต้องมีหน่วยเดียวกัน หรือเมื่อ variance ของตัวแปร X มีความสำคัญหรือใช้สื่อความหมายอะไรบางอย่าง ส่วนถ้าตัวแปรเรามีหน่วยต่างกัน (เช่น ตัวแปร น้ำหนัก หน่วยเป็น กิโลกรัม กับ ตัวแปร ระยาทาง หน่วยเป็น เมตร) ก็ให้ทำ Standardized ก่อนแล้วใช้ Correlation แทน (Correlation น่าจะปลอดภัยกว่า)
#ทำการหา Co-variance ของตัวแปรจาก data
S <- cov(X)
หลังจากที่ได้ Covariance Matrix (หรือ Correlation Matrix) มาแล้วเราก็มาหา Eigenvector กับ Eigenvalue ของ Covariance Matrix กัน ซึ่ง Eigenvalue ก็คือค่า variance ของ component ส่วน Eigenvector ก็คือค่าสัมประสิทธิ์ของตัวแปร X ตามที่อธิบายไว้ข้างบน
#ทำการหา Eigenvector กับ Eigenvalue ของ Co-variance Matrix
Eigen <- eigen(S)
eigenvalue <- Eigen$values
eigenvector <- Eigen$vectors
สุดท้ายเราก็มาดูว่า component ที่สร้างมาแต่ละตัวใช้อธิบาย variance ของ population ได้กี่เปอร์เซ็นต์ ส่วนว่าจะใช้กี่ตัวก็เอา เปอร์เซ็นต์ที่หามาได้ บวกกัน ถ้าได้เกิน 80–90 % ก็ถือว่าใช้ได้แล้วครับ
#สร้างกราฟ Scree plot กับ Cumulative plot
options(repr.plot.width=8, repr.plot.height=4)
par(mfrow=c(1,2),mar=c(3,3,3,3) )per_var <- eigenvalue/sum(eigenvalue)*100
cum_var <- cumsum(per_var)plot(per_var[1:150], xlab = “Component number”,
ylab = “Component variance”, type = “l”, main = “Scree diagram”)
plot(cum_var[1:150], xlab = “Component number”,
ylab = “Component variance”, type = “l”, main = “cumulative diagram”)
จาก Scree plot กับ Cumulative plot ถ้าเราใช้ component จำนวน 100 ก็จะสามารถอธิบาย information ของข้อมูลเราเกือบ 100% มาลอง plot Eigenvector ที่เราได้ดีกว่าว่าจะมีหน้าตาออกมาประมาณไหน
options(repr.plot.width=8, repr.plot.height=8)
par(mfrow=c(10,10),mar=c(0,0,0,0) )
for (i in 1:100) {
t1 <- matrix(data=rev(t(eigenvector[,i])), nrow=96, ncol=96)
plot1 <- image(1:96, 1:96, t1, col=gray((0:255)/255),xaxt=’n’,yaxt=’n’, ann=FALSE)
}
ซึ่งปกติ Eigenvector พวกนี้จะถูกเรียกว่า EigenFace ในการทำ face recognition
เราลองเอา component ที่เราได้มาสร้างกลับเป็นหน้าดูว่าจะได้เหมือนต้นฉบับมั้ย
# ลองใช้ component 20, 50, 100 ตัวมาสร้างกลับเป็นหน้าคน
library(matlib)
PCA20 <- X%*%eigenvector[,1:20]
PCA50 <- X%*%eigenvector[,1:50]
PCA100 <- X%*%eigenvector[,1:100]options(repr.plot.width=8, repr.plot.height=6)
par(mfrow=c(3,4),mar=c(2,2,2,2) )# ลอง plot ดูสัก 2 หน้า
for (i in 1:2){t1 <- matrix(data=rev(im.train[i,]), nrow=96, ncol=96)
plot1 <- image(1:96, 1:96, t1, col=gray((0:255)/255))
title(main = "Original")pca20 <- matrix(data=rev(PCA20[i,]%*%t(eigenvector[,1:20])), nrow=96, ncol=96)
pcaplot1 <- image(1:96, 1:96, pca20, col=gray((0:255)/255))
title(main = "PCA20")pca50 <- matrix(data=rev(PCA50[i,]%*%t(eigenvector[,1:50])), nrow=96, ncol=96)
pcaplot2 <- image(1:96, 1:96, pca50, col=gray((0:255)/255))
title(main = "PCA50")pca100 <- matrix(data=rev(PCA[i,]%*%t(eigenvector[,1:100])), nrow=96, ncol=96)
pcaplot4 <- image(1:96, 1:96, pca100, col=gray((0:255)/255))
title(main = "PCA100")
}
พอ reconstruct กลับมาแล้วยังดูไม่เนียนเท่าไหร่ เรามาลอง process data เพิ่มขึ้นหน่อยโดยการเอารูปแต่ละรูปมาลบกับค่าเฉลี่ย
#หาค่าเฉลี่ยก่อน
options(repr.plot.width=3, repr.plot.height=3)
par(mfrow=c(1,1),mar=c(2,2,2,2) )
average_face <- colMeans(im.train)
t1 <- matrix(data=rev(average_face), nrow=96, ncol=96)
plot1 <- image(1:96, 1:96, t1, col=gray((0:255)/255))
title(main = “Average Face”)
substract_face <- apply(im.train,1,’-’,average_face)
S2 <- cov(t(substract_face))
dim(S2)
s_Eigen <- eigen(S2)
s_eigenvalue <- s_Eigen$values
s_eigenvector <- s_Eigen$vectorsS_PCA20 <- t(substract_face)%*%s_eigenvector[,1:20]
S_PCA50 <- t(substract_face)%*%s_eigenvector[,1:50]
S_PCA100 <- t(substract_face)%*%s_eigenvector[,1:100]options(repr.plot.width=8, repr.plot.height=6)
par(mfrow=c(3,4),mar=c(2,2,2,2) )
for (i in 1:2){# ตอน reconstruct เราต้องบวกค่า average ที่เราลบออกไปตอนแรกกลับมาด้วย
t1 <- matrix(data=rev(t(substract_face[,i])+t(average_face)), nrow=96, ncol=96)
# t1 <- matrix(data=rev(apply(t(substract_face[,i]),1,'+',t(average_face))), nrow=96, ncol=96)
plot1 <- image(1:96, 1:96, t1, col=gray((0:255)/255))
title(main = "Original")
s_pca20 <- matrix(data=rev((S_PCA20[i,]%*%t(s_eigenvector[,1:20]))+t(average_face)), nrow=96, ncol=96)
pcaplot1 <- image(1:96, 1:96, s_pca20, col=gray((0:255)/255))
title(main = "PCA20")s_pca50 <- matrix(data=rev((S_PCA50[i,]%*%t(s_eigenvector[,1:50]))+t(average_face)), nrow=96, ncol=96)
pcaplot2 <- image(1:96, 1:96, s_pca50, col=gray((0:255)/255))
title(main = "PCA50")s_pca100 <- matrix(data=rev((S_PCA100[i,]%*%t(s_eigenvector[,1:100]))+t(average_face)), nrow=96, ncol=96)
pcaplot4 <- image(1:96, 1:96, s_pca100, col=gray((0:255)/255))
title(main = "PCA100")
}
ดูเนียนขึ้นมาละ ตอนนี้เอาไว้แค่นี้ก่อน หวังว่า story นี้จะช่วยให้ทุกท่านเข้าใจ PCA มากขึ้น โดยในตอนหน้า ผมจะมาต่อเรื่อง Factor Analysis โดยจะแสดงให้เห็นถึงความแตกต่างระหว่าง Factor Analysis กับ Principal Component Analysis