ลูกศรของตัวแปรพื้นฐานใน PCA biplot ใน R


11

ด้วยความเสี่ยงในการสร้างคำถามเฉพาะซอฟต์แวร์และด้วยข้ออ้างเกี่ยวกับความแพร่หลายและความแปลกประหลาดของมันฉันต้องการถามเกี่ยวกับฟังก์ชั่นbiplot()ใน R และโดยเฉพาะอย่างยิ่งมากขึ้นเกี่ยวกับการคำนวณและการวางแผนของลูกศรสีแดงซ้อน ไปยังตัวแปรพื้นฐาน


[เพื่อให้เข้าใจถึงความคิดเห็นบางส่วนในตอนแรกแผนการที่โพสต์มีปัญหาที่น่าสนใจอย่างมากและตอนนี้ถูกลบไปแล้ว]


ฉันไม่สามารถทราบได้ว่าคุณมีลูกศรสีเขียวของคุณอย่างไร พวกเขาไม่ถูกต้อง ความจริงที่ว่า s.length green นั้นประมาณ ยาวกว่า s.width สีเขียวสองเท่าช่วยให้คุณสงสัยว่าคุณกำลังพล็อตเวกเตอร์ที่เกี่ยวข้องกับตัวแปรที่ไม่ได้มาตรฐาน สิ่งเหล่านี้ไม่สามารถเกิดขึ้นได้บน biplot ของ PCA ตามสหสัมพันธ์
ttnphns

ลูกศรสีแดงดูถูกต้อง ดู: มันมีความยาวเท่ากันและมีความสมมาตรกับ PC2 นั่นเป็นตำแหน่งที่เป็นไปได้เฉพาะเมื่อคุณทำ PCA ที่มีเพียง 2 ตัวแปรและขึ้นอยู่กับความสัมพันธ์ (เช่นตัวแปรมาตรฐาน) ใน PCA ตามสหสัมพันธ์การโหลด (การประสานงานของลูกศร) คือความสัมพันธ์ระหว่างพีซีและตัวแปร ในตัวอย่างของแรงที่มี (vars .74752, .66424; -.74752, .66424โดยพีซี):
ttnphns

@ttnphns ใช่ลูกศรสีแดงเป็นสิ่งที่ฉันพยายามที่จะทำซ้ำ (ถูกต้อง) และพวกเขาจะวางแผนในการวิจัยกับการเรียกร้องซึ่งในกรณีนี้คือbiplot(name_of_the_PCA) biplot(PCA)ฉันมีศูนย์กลางและปรับขนาดข้อมูล
Antoni Parellada

ดังนั้นคำถามของคุณคืออะไร วิธีคำนวณพิกัดของลูกศรสีแดง พวกเขาควรจะ PCA แรง บางครั้งมีการวางแผน eigenvectors (R คำสั่งของคุณอาจจะไม่ ?? นั้น) แต่ความยินยอมทางความหมายคือการเติมพล็อต
ttnphns

@ttnphns พล็อต eigenvectors (ฉันคิดว่ามันเหมือนกับโหลด) ทำให้ฉันมีทิศทางที่ถูกต้อง (ขอบคุณ) แต่ไม่ได้มีขนาดเท่ากับลูกศรสีแดง (ฉันวางภาพใน OP)
Antoni Parellada

คำตอบ:


19

พิจารณา upvoting @ อะมีบาของและโพสต์ @ttnphns' ขอบคุณทั้งสำหรับความช่วยเหลือและความคิดของคุณ


ต่อไปนี้จะอาศัยการทำงานของชุดข้อมูลที่ไอริสในการวิจัยและโดยเฉพาะสามตัวแปรแรก Sepal.Length, Sepal.Width, Petal.Length(คอลัมน์):

biplotรวมพล็อตในการโหลด (eigenvectors unstandardized) - ในคอนกรีตทั้งสองครั้งแรกที่แรงและพล็อตคะแนน (หมุนและพองจุดข้อมูลที่พล็อตที่เกี่ยวกับองค์ประกอบหลัก) ใช้ชุดเดียวกัน@amoeba อธิบาย 9 รวมกันเป็นไปได้ของ PCA biplotขึ้นอยู่กับ3 normalizations เป็นไปได้ของพล็อตคะแนนขององค์ประกอบหลักเป็นครั้งแรกและครั้งที่สองและ(ลูกศร) 3 normalizations ของพล็อตในการโหลดของตัวแปรเริ่มต้น หากต้องการดูว่า 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 a 1 a 2 V PC 1 PC 2VSepal L.ha1a2VPC1PC2


ป้อนคำอธิบายรูปภาพที่นี่


ส่วนประกอบของตัวแปรที่Sepal L.เกี่ยวข้องกับจะเป็น:PC1

a1=hcos(ϕ)

ซึ่งหากคะแนนที่เกี่ยวข้องกับ - เรียกมันว่า - เป็นมาตรฐานเพื่อให้พวกเขาเอส1PC1S1

S1=1nscores12=1สมการข้างต้นนั้นเทียบเท่ากับจุดของผลิตภัณฑ์ :VS1

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

ตั้งแต่ ,V=x2

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

ในทำนองเดียวกัน

S1=1=var(S1)n1.

กลับไปที่ Eq ,(1)

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

cos(ϕ)สามารถจึงได้รับการพิจารณาค่าสัมประสิทธิ์สหสัมพันธ์ของเพียร์สัน ,มีข้อแม้ที่ว่าฉันไม่เข้าใจริ้วรอยของปัจจัยrn1

การทำซ้ำและทับซ้อนในสีน้ำเงินลูกศรสีแดงของ 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)

ป้อนคำอธิบายรูปภาพที่นี่

จุดที่น่าสนใจ:

  • ลูกศรสามารถทำซ้ำได้ตามความสัมพันธ์ของตัวแปรดั้งเดิมด้วยคะแนนที่สร้างขึ้นโดยองค์ประกอบหลักสองประการแรก
  • หรือสามารถทำได้เช่นเดียวกับพล็อตแรกในแถวที่สองที่มีข้อความในโพสต์ของ @ amoeba:VS

ป้อนคำอธิบายรูปภาพที่นี่

หรือในรหัส 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

  • มีปัจจัยการปรับขนาด: sqrt(nrow(X) - 1)ซึ่งยังคงเป็นบิตของความลึกลับ

  • 0.8เกี่ยวข้องกับการสร้างพื้นที่สำหรับป้ายกำกับ - ดูความคิดเห็นนี้ที่นี่ :

ยิ่งไปกว่านั้นเราควรจะบอกว่าลูกศรถูกวางแผนเช่นนั้นจุดศูนย์กลางของป้ายข้อความคือที่ที่มันควรจะเป็น! ลูกศรจะถูกคูณด้วย 0.80.8 ก่อนทำการพล็อตนั่นคือลูกศรทั้งหมดจะสั้นกว่าที่ควรจะเป็นเพื่อป้องกันการซ้อนทับกับป้ายข้อความ (ดูรหัสสำหรับ biplot.default) ฉันพบว่ามันสับสนอย่างยิ่ง - อะมีบา 19 มีนาคม '15 ที่ 10:06


2. การพล็biplot()อตคะแนน (และลูกศรพร้อมกัน):

แกนถูกปรับสัดส่วนให้เป็นผลรวมของหน่วยสี่เหลี่ยมซึ่งสอดคล้องกับพล็อตแรกของแถวแรกบนโพสต์ของ @ amoebaซึ่งสามารถทำซ้ำการวางแผนเมทริกซ์ของการย่อยสลาย svd (เพิ่มเติมในภายหลัง) - " คอลัมน์ของ : เหล่านี้เป็นองค์ประกอบหลักปรับขนาดให้หน่วยผลรวมของสี่เหลี่ยม. "UU

ป้อนคำอธิบายรูปภาพที่นี่

มีเครื่องชั่งสองแบบที่ต่างกันที่เล่นบนแกนแนวนอนด้านล่างและด้านบนในการสร้าง biplot:

ป้อนคำอธิบายรูปภาพที่นี่

อย่างไรก็ตามระดับสัมพัทธ์ไม่ชัดเจนในทันทีต้องทำการขุดเข้าไปในฟังก์ชั่นและวิธีการ:

biplot()พล็อตคะแนนเป็นคอลัมน์ของใน SVD ซึ่งเป็นหน่วยเวกเตอร์มุมฉาก: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

แต่เนื่องจากเราต้องการผลรวมของกำลังสองเป็นเราจะต้องหารด้วยเพราะ: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

จากการสังเกตการใช้ตัวคูณมาตราส่วนจะถูกเปลี่ยนเป็นในภายหลังเมื่อกำหนดคำอธิบายที่ดูเหมือนจะโกหกในความจริงที่ว่าn1nlan

prcompใช้ : "ไม่เหมือนกับ princomp ความแปรปรวนจะถูกคำนวณด้วยตัวหารปกติ "n1n1


หลังจากที่พวกเขาออกจาก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 แสดงความคิดเห็น:

พล็อตการกระจายและ "พล็อตลูกศร" ถูกปรับอัตราส่วนให้มากที่สุด (ในค่าสัมบูรณ์) x หรือ y พิกัดลูกศรของลูกศรเท่ากับค่าที่ใหญ่ที่สุด (ในค่าสัมบูรณ์) x หรือ y พิกัดจุดข้อมูลที่กระจัดกระจาย

  • ตามที่คาดไว้ข้างต้นคะแนนสามารถวางแผนโดยตรงเป็นคะแนนในเมทริกซ์ของ SVD:U


1
+1, การศึกษาที่ดี ฉันเพิ่มแท็กRในคำถามของคุณเพราะเรื่องที่สับสน (กล่าวคือค่าสัมประสิทธิ์การปรับสเกล) พิสูจน์แล้วว่าเป็นค่าเฉพาะส่วน R โดยทั่วไปคุณสามารถเห็นตัวเองว่า PCA biplot เป็น scatterplot แบบซ้อนทับของคะแนนองค์ประกอบ (พิกัดแถว) และค่าสัมประสิทธิ์ทิศทางส่วนประกอบ (พิกัดคอลัมน์) และเนื่องจากจำนวนต่าง ๆ ของมาตรฐานโดย "inertia" (ความแปรปรวน) อาจนำไปใช้กับแต่ละ ของเช่นกันดังนั้นรูปลักษณ์ที่หลากหลายของ biplot อาจเกิดขึ้น ในการเพิ่ม: โดยทั่วไปแล้ว (มีความหมายมากกว่า) การโหลดจะปรากฏเป็นพิกัดคอลัมน์ (ลูกศร)
ttnphns

1
(ต่อ) ดูภาพรวมของฉันของbiplotซึ่งอธิบายในคำต่าง ๆ สิ่งที่คุณแสดงในคำตอบที่ดีของคุณ
ttnphns

2
+ 1 ขอบคุณสำหรับการเขียนบทช่วยสอนและด้วยรหัสที่ทำซ้ำได้สำหรับเรา!
Haitao Du

แอนโทนีคุณวาด (ตามด้วยมือ) หรือคุณวางแผน (ป้อนข้อมูล) รูปของคุณหรือไม่ คุณใช้ซอฟต์แวร์อะไร มันดูดี
ttnphns

@ttnphns ขอบคุณ! นี่คือการเชื่อมโยงกับมัน ฉันสงสัยว่าคุณจะปรับปรุงได้หรือไม่และวางแผนการโหลดและพีซีในแบบที่ดีกว่า อย่าลังเลที่จะเปลี่ยน (มันเป็นโปรแกรมที่ใช้งานง่ายอย่างยิ่ง) และถ้าคุณทำโปรดแบ่งปัน
Antoni Parellada
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.