Làm thế nào để xác định các thành phần chính quan trọng bằng cách sử dụng phương pháp bootstrapping hoặc Monte Carlo?


40

Tôi quan tâm đến việc xác định số lượng mẫu quan trọng được đưa ra từ Phân tích thành phần chính (PCA) hoặc Phân tích chức năng trực giao thực nghiệm (EOF). Tôi đặc biệt quan tâm đến việc áp dụng phương pháp này vào dữ liệu khí hậu. Trường dữ liệu là ma trận MxN với M là thứ nguyên thời gian (ví dụ: ngày) và N là thứ nguyên không gian (ví dụ: vị trí lon / lat). Tôi đã đọc một phương pháp bootstrap có thể để xác định các PC quan trọng, nhưng không thể tìm thấy một mô tả chi tiết hơn. Cho đến bây giờ, tôi vẫn đang áp dụng Quy tắc ngón tay cái của North (North et al ., 1982) để xác định điểm cắt này, nhưng tôi tự hỏi liệu có phương pháp nào mạnh mẽ hơn không.

Ví dụ:

###Generate data
x <- -10:10
y <- -10:10
grd <- expand.grid(x=x, y=y)

#3 spatial patterns
sp1 <- grd$x^3+grd$y^2
tmp1 <- matrix(sp1, length(x), length(y))
image(x,y,tmp1)

sp2 <- grd$x^2+grd$y^2
tmp2 <- matrix(sp2, length(x), length(y))
image(x,y,tmp2)

sp3 <- 10*grd$y
tmp3 <- matrix(sp3, length(x), length(y))
image(x,y,tmp3)


#3 respective temporal patterns
T <- 1:1000

tp1 <- scale(sin(seq(0,5*pi,,length(T))))
plot(tp1, t="l")

tp2 <- scale(sin(seq(0,3*pi,,length(T))) + cos(seq(1,6*pi,,length(T))))
plot(tp2, t="l")

tp3 <- scale(sin(seq(0,pi,,length(T))) - 0.2*cos(seq(1,10*pi,,length(T))))
plot(tp3, t="l")


#make data field - time series for each spatial grid (spatial pattern multiplied by temporal pattern plus error)
set.seed(1)
F <- as.matrix(tp1) %*% t(as.matrix(sp1)) + 
as.matrix(tp2) %*% t(as.matrix(sp2)) + 
as.matrix(tp3) %*% t(as.matrix(sp3)) +
matrix(rnorm(length(T)*dim(grd)[1], mean=0, sd=200), nrow=length(T), ncol=dim(grd)[1]) # error term

dim(F)
image(F)


###Empirical Orthogonal Function (EOF) Analysis 
#scale field
Fsc <- scale(F, center=TRUE, scale=FALSE)

#make covariance matrix
C <- cov(Fsc)
image(C)

#Eigen decomposition
E <- eigen(C)

#EOFs (U) and associated Lambda (L) 
U <- E$vectors
L <- E$values

#projection of data onto EOFs (U) to derive principle components (A)
A <- Fsc %*% U

dim(U)
dim(A)

#plot of top 10 Lambda
plot(L[1:10], log="y")

#plot of explained variance (explvar, %) by each EOF
explvar <- L/sum(L) * 100
plot(explvar[1:20], log="y")


#plot original patterns versus those identified by EOF
layout(matrix(1:12, nrow=4, ncol=3, byrow=TRUE), widths=c(1,1,1), heights=c(1,0.5,1,0.5))
layout.show(12)

par(mar=c(4,4,3,1))
image(tmp1, main="pattern 1")
image(tmp2, main="pattern 2")
image(tmp3, main="pattern 3")

par(mar=c(4,4,0,1)) 
plot(T, tp1, t="l", xlab="", ylab="")
plot(T, tp2, t="l", xlab="", ylab="")
plot(T, tp3, t="l", xlab="", ylab="")

par(mar=c(4,4,3,1))
image(matrix(U[,1], length(x), length(y)), main="eof 1") 
image(matrix(U[,2], length(x), length(y)), main="eof 2")
image(matrix(U[,3], length(x), length(y)), main="eof 3")

par(mar=c(4,4,0,1)) 
plot(T, A[,1], t="l", xlab="", ylab="")
plot(T, A[,2], t="l", xlab="", ylab="")
plot(T, A[,3], t="l", xlab="", ylab="")

nhập mô tả hình ảnh ở đây

Và, đây là phương pháp mà tôi đã và đang sử dụng để xác định tầm quan trọng của PC. Về cơ bản, nguyên tắc chung là sự khác biệt giữa Lambdas lân cận phải lớn hơn lỗi liên quan của chúng.

###Determine significant EOFs

#North's Rule of Thumb
Lambda_err <- sqrt(2/dim(F)[2])*L
upper.lim <- L+Lambda_err
lower.lim <- L-Lambda_err
NORTHok=0*L
for(i in seq(L)){
    Lambdas <- L
    Lambdas[i] <- NaN
    nearest <- which.min(abs(L[i]-Lambdas))
    if(nearest > i){
        if(lower.lim[i] > upper.lim[nearest]) NORTHok[i] <- 1
    }
    if(nearest < i){
        if(upper.lim[i] < lower.lim[nearest]) NORTHok[i] <- 1
    }
}
n_sig <- min(which(NORTHok==0))-1

plot(L[1:10],log="y", ylab="Lambda (dots) and error (vertical lines)", xlab="EOF")
segments(x0=seq(L), y0=L-Lambda_err, x1=seq(L), y1=L+Lambda_err)
abline(v=n_sig+0.5, col=2, lty=2)
text(x=n_sig, y=mean(L[1:10]), labels="North's Rule of Thumb", srt=90, col=2)

nhập mô tả hình ảnh ở đây

Tôi đã tìm thấy phần chương của Bjornsson và Venegas ( 1997 ) về các bài kiểm tra quan trọng là hữu ích - chúng đề cập đến ba loại bài kiểm tra, trong đó phương sai chiếm ưu thế có lẽ là điều tôi hy vọng sẽ sử dụng. Việc đề cập đến một kiểu tiếp cận Monte Carlo về xáo trộn kích thước thời gian và tính toán lại Lambdas qua nhiều hoán vị. von Storch và Zweiers (1999) cũng đề cập đến một thử nghiệm so sánh phổ Lambda với phổ "nhiễu" tham chiếu. Trong cả hai trường hợp, tôi hơi không chắc chắn về cách thức này có thể được thực hiện và cũng như cách kiểm tra ý nghĩa được thực hiện với các khoảng tin cậy được xác định bởi các hoán vị.

Cảm ơn bạn đã giúp đỡ.

Tài liệu tham khảo: Bjornsson, H. và Venegas, SA (1997). "Hướng dẫn phân tích dữ liệu khí hậu EOF và SVD", Đại học McGill, Báo cáo CCGCR số 97-1, Montréal, Québec, 52pp. http://andvari.vedur.is/%7Efolk/halldor/PICKUP/eof.pdf

GR North, TL Bell, RF Cahalan và FJ Moeng. (1982). Lỗi lấy mẫu trong ước lượng các hàm trực giao theo kinh nghiệm. Thứ Hai Dệt. Rev., 110: 699 Từ706.

von Storch, H, Zwiers, FW (1999). Phân tích thống kê trong nghiên cứu khí hậu. Nhà xuất bản Đại học Cambridge.


Tài liệu tham khảo của bạn về phương pháp bootstrap là gì?
Michael Chernick

4
Một bootstrap sẽ không hoạt động ở đây. Nó sẽ không hoạt động với các tập dữ liệu trong đó hầu hết mọi quan sát đều tương quan với hầu hết các quan sát khác; nó cần sự độc lập, hoặc ít nhất là tính độc lập gần đúng (các điều kiện trộn trong chuỗi thời gian, giả sử) để tạo ra các bản sao chính xác của dữ liệu. Tất nhiên có những chương trình bootstrap đặc biệt, như bootstrap hoang dã, có thể tránh được những vấn đề này. Nhưng tôi sẽ không đặt cược nhiều vào điều này. Và bạn thực sự cần phải xem các cuốn sách thống kê đa biến, và theo dõi chúng, để không nhận được một cây gậy khúc côn cầu không thể bảo vệ khác như một câu trả lời.
StasK

2
@Marc trong hộp bạn có thể đề cập đến các bootstraps khối khác nhau được sử dụng cho chuỗi thời gian, MBB (bootstrap khối di chuyển) CBB (bootstrap khối tròn) hoặc SBB (bootstrap khối tĩnh) sử dụng các khối thời gian của dữ liệu để ước tính mô hình thông số.
Michael Chernick

3
@StasK Tôi không biết lý do tại sao bạn nghĩ rằng bạn cần các điều kiện trộn để áp dụng bootstrap vào chuỗi thời gian. Các phương thức dựa trên mô hình chỉ yêu cầu bạn phù hợp với cấu trúc chuỗi thời gian và sau đó bạn có thể bootstrap dư. Vì vậy, bạn có thể có chuỗi thời gian với các xu hướng và các thành phần theo mùa và vẫn thực hiện bootstrap dựa trên mô hình.
Michael Chernick

2
Tôi không có quyền truy cập vào toàn văn nhưng bạn có thể thử xem: "Hamid Babamoradi, Frans van den Berg, Åsmund Rinnan, giới hạn độ tin cậy dựa trên Bootstrap trong phân tích thành phần chính - Một nghiên cứu trường hợp, Hệ thống phòng thí nghiệm hóa học và thông minh, Khối lượng 120, 15 tháng 1 năm 2013, Trang 97-105, ISSN 0169-7439, 10.1016 / j.chemolab.2012.10.007. ( Scazedirect.com/science/article/pii/S0169743912002171 ) Từ khóa: Bootstrap; PCA; Giới hạn tin cậy; sub> a </ sub>; Không chắc chắn "
tomasz74

Câu trả lời:


19

Tôi sẽ cố gắng và thúc đẩy cuộc đối thoại ở đây một chút mặc dù đây là câu hỏi của tôi. Đã 6 tháng kể từ khi tôi hỏi điều này và thật không may, không có câu trả lời hoàn chỉnh nào được đưa ra, tôi sẽ thử và tóm tắt những gì tôi đã thu thập được cho đến nay và xem liệu có ai có thể giải thích về các vấn đề còn lại không. Xin thứ lỗi cho câu trả lời dài dòng, nhưng tôi không còn cách nào khác ...

Đầu tiên, tôi sẽ trình bày một số cách tiếp cận bằng cách sử dụng bộ dữ liệu tổng hợp có thể tốt hơn. Nó xuất phát từ một bài báo của Beckers và Rixon ( 2003 ) minh họa việc sử dụng thuật toán để tiến hành EOF trên dữ liệu vui vẻ. Tôi đã sao chép thuật toán trong R nếu có ai quan tâm ( link ).

Tập dữ liệu tổng hợp:

#color palette
pal <- colorRampPalette(c("blue", "cyan", "yellow", "red"))

#Generate data
m=50
n=100
frac.gaps <- 0.5 # the fraction of data with NaNs
N.S.ratio <- 0.25 # the Noise to Signal ratio for adding noise to data

x <- (seq(m)*2*pi)/m
t <- (seq(n)*2*pi)/n


#True field
Xt <- 
 outer(sin(x), sin(t)) + 
 outer(sin(2.1*x), sin(2.1*t)) + 
 outer(sin(3.1*x), sin(3.1*t)) +
 outer(tanh(x), cos(t)) + 
 outer(tanh(2*x), cos(2.1*t)) + 
 outer(tanh(4*x), cos(0.1*t)) + 
 outer(tanh(2.4*x), cos(1.1*t)) + 
 tanh(outer(x, t, FUN="+")) + 
 tanh(outer(x, 2*t, FUN="+"))

Xt <- t(Xt)
image(Xt, col=pal(100))

#Noise field
set.seed(1)
RAND <- matrix(runif(length(Xt), min=-1, max=1), nrow=nrow(Xt), ncol=ncol(Xt))
R <- RAND * N.S.ratio * Xt

#True field + Noise field
Xp <- Xt + R
image(Xp, col=pal(100))

nhập mô tả hình ảnh ở đây

Vì vậy, trường dữ liệu thực sự Xtbao gồm 9 tín hiệu và tôi đã thêm một số nhiễu vào nó để tạo trường quan sát Xp, sẽ được sử dụng trong các ví dụ dưới đây. Các EOF được xác định như sau:

EOF

#make covariance matrix
C <- t(Xp) %*% Xp #cov(Xp)
image(C)

#Eigen decomposition
E <- svd(C)

#EOFs (U) and associated Lambda (L) 
U <- E$u
L <- E$d

#projection of data onto EOFs (U) to derive principle components (A)
A <- Xp %*% U

Theo ví dụ mà tôi đã sử dụng trong ví dụ ban đầu của mình, tôi sẽ xác định các EOF "đáng kể" thông qua quy tắc ngón tay cái của North.

Quy tắc của Bắc

Lambda_err <- sqrt(2/dim(Xp)[2])*L
upper.lim <- L+Lambda_err
lower.lim <- L-Lambda_err
NORTHok=0*L
for(i in seq(L)){
    Lambdas <- L
    Lambdas[i] <- NaN
    nearest <- which.min(abs(L[i]-Lambdas))
    if(nearest > i){
        if(lower.lim[i] > upper.lim[nearest]) NORTHok[i] <- 1
    }
    if(nearest < i){
        if(upper.lim[i] < lower.lim[nearest]) NORTHok[i] <- 1
    }
}
n_sig <- min(which(NORTHok==0))-1
n_sig

plot(L[1:20],log="y", ylab="Lambda (dots) and error (vertical lines)", xlab="EOF")
segments(x0=seq(L), y0=L-Lambda_err, x1=seq(L), y1=L+Lambda_err)
abline(v=n_sig+0.5, col=2, lty=2)
text(x=n_sig, y=mean(L[1:10]), labels="North's Rule of Thumb", srt=90, col=2)

nhập mô tả hình ảnh ở đây

Do các giá trị Lambda là 2: 4 rất gần nhau về biên độ, nên chúng được coi là không đáng kể theo quy tắc ngón tay cái - tức là các mẫu EOF tương ứng của chúng có thể chồng lên nhau và trộn với các biên độ tương tự của chúng. Điều này thật đáng tiếc khi chúng ta biết rằng 9 tín hiệu thực sự tồn tại trong trường.

Một cách tiếp cận chủ quan hơn là xem các giá trị Lambda được chuyển đổi nhật ký ("Biểu đồ Scree") và sau đó điều chỉnh hồi quy cho các giá trị theo sau. Sau đó, người ta có thể xác định trực quan ở mức độ nào các giá trị lambda nằm trên dòng này:

Âm mưu

ntrail <- 35
tail(L, ntrail)
fit <- lm(log(tail(L, ntrail)) ~ seq(length(L)-ntrail+1, length(L)))
plot(log(L))
abline(fit, col=2)

nhập mô tả hình ảnh ở đây

Vì vậy, 5 EOF hàng đầu nằm trên dòng này. Tôi đã thử ví dụ này khi Xpkhông có thêm nhiễu và kết quả cho thấy tất cả 9 tín hiệu ban đầu. Vì vậy, mức độ không đáng kể của EOF 6: 9 là do biên độ của chúng thấp hơn nhiễu trong trường.

Một phương pháp khách quan hơn là tiêu chí "Quy tắc N" của Overland và Preisendorfer (1982). Có một triển khai trong wqgói, mà tôi hiển thị dưới đây.

Quy tắc N

library(wq)
eofNum(Xp, distr = "normal", reps = 99)

RN <- ruleN(nrow(Xp), ncol(Xp), type = "normal", reps = 99)
RN
eigs <- svd(cov(Xp))$d
plot(eigs, log="y")
lines(RN, col=2, lty=2)

nhập mô tả hình ảnh ở đây

Quy tắc N đã xác định 4 EOF đáng kể. Cá nhân, tôi cần hiểu rõ hơn về phương pháp này; Tại sao có thể đánh giá mức độ lỗi dựa trên một trường ngẫu nhiên không sử dụng phân phối giống như trong phân phối đó Xp? Một biến thể của phương pháp này sẽ là lấy mẫu lại dữ liệu Xpđể mỗi cột được chia sẻ lại một cách ngẫu nhiên. Theo cách này, chúng tôi đảm bảo rằng tổng phương sai của trường ngẫu nhiên giống như Xp. Bằng cách lấy mẫu lại nhiều lần, sau đó chúng tôi có thể tính toán một lỗi cơ sở của quá trình phân tách.

Monte Carlo với trường ngẫu nhiên (ví dụ so sánh mô hình Null)

iter <- 499
LAMBDA <- matrix(NaN, ncol=iter, nrow=dim(Xp)[2])

set.seed(1)
for(i in seq(iter)){
    #i=1

    #random reorganize dimensions of scaled field
    Xp.tmp <- NaN*Xp
    for(j in seq(dim(Xp.tmp)[2])){
        #j=1
        Xp.tmp[,j] <- Xp[,j][sample(nrow(Xp))]
    }

    #make covariance matrix
    C.tmp <- t(Xp.tmp) %*% Xp.tmp #cov(Xp.tmp)

    #SVD decomposition
    E.tmp <- svd(C.tmp)

    #record Lambda (L) 
    LAMBDA[,i] <- E.tmp$d

    print(paste(round(i/iter*100), "%", " completed", sep=""))
}

boxplot(t(LAMBDA), log="y", col=8, border=2, outpch="")
points(L)

nhập mô tả hình ảnh ở đây

Một lần nữa, 4 EOF nằm trên các bản phân phối cho các trường ngẫu nhiên. Lo lắng của tôi với cách tiếp cận này, và của Quy tắc N, là những điều này không thực sự giải quyết các khoảng tin cậy của các giá trị Lambda; ví dụ: giá trị Lambda cao đầu tiên sẽ tự động dẫn đến lượng phương sai thấp hơn được giải thích bằng các giá trị dấu. Do đó, Lambda được tính toán từ các trường ngẫu nhiên sẽ luôn có độ dốc thấp hơn và có thể dẫn đến việc chọn quá ít EOF đáng kể. [LƯU Ý: eofNum()Hàm giả định rằng EOF được tính từ ma trận tương quan. Con số này có thể khác nếu sử dụng ma trận hiệp phương sai (tập trung nhưng không thu nhỏ dữ liệu).]

Cuối cùng, @ tomasz74 đã đề cập đến bài báo của Babamoradi et al. (2013), mà tôi đã có một cái nhìn ngắn gọn về. Nó rất thú vị, nhưng dường như tập trung hơn vào việc tính toán các hệ số và hệ số EOF của CI, thay vì Lambda. Tuy nhiên, tôi tin rằng có thể áp dụng để đánh giá lỗi Lambda bằng phương pháp tương tự. Việc lấy mẫu bootstrap được thực hiện cho trường dữ liệu bằng cách lấy lại các hàng cho đến khi một trường mới được tạo. Cùng một hàng có thể được ghép lại nhiều lần, đó là một cách tiếp cận không tham số và người ta không cần phải đưa ra các giả định về việc phân phối dữ liệu.

Bootstrap của giá trị Lambda

B <- 40 * nrow(Xp)
LAMBDA <- matrix(NaN, nrow=length(L), ncol=B)
for(b in seq(B)){
    samp.b <- NaN*seq(nrow(Xp))
    for(i in seq(nrow(Xp))){
        samp.b[i] <- sample(nrow(Xp), 1)
    }
    Xp.b  <- Xp[samp.b,]
    C.b  <- t(Xp.b) %*% Xp.b 
    E.b  <- svd(C.b)
    LAMBDA[,b] <- E.b$d
    print(paste(round(b/B*100), "%", " completed", sep=""))
}
boxplot(t(LAMBDA), log="y", col=8, outpch="", ylab="Lambda [log-scale]")
points(L, col=4)
legend("topright", legend=c("Original"), pch=1, col=4)

nhập mô tả hình ảnh ở đây

Mặc dù điều này có thể mạnh hơn quy tắc ngón tay cái của Bắc để tính toán sai số của các giá trị Lambda, tôi tin rằng bây giờ câu hỏi về tầm quan trọng của EOF đưa ra các ý kiến ​​khác nhau về ý nghĩa của điều này. Đối với phương pháp ngón tay cái và phương pháp bootstrap của miền Bắc, tầm quan trọng dường như dựa nhiều hơn vào việc teere có trùng nhau giữa các giá trị Lambda hay không. Nếu có, thì các EOF này có thể được trộn lẫn trong các tín hiệu của chúng và không đại diện cho các mẫu "thật". Mặt khác, hai EOF này có thể mô tả một lượng phương sai đáng kể (so với sự phân tách của một trường ngẫu nhiên - ví dụ Quy tắc N). Vì vậy, nếu một người quan tâm đến việc lọc tiếng ồn (tức là thông qua cắt bớt EOF) thì Quy tắc N sẽ là đủ. Nếu một người quan tâm đến việc xác định các mẫu thực trong một tập dữ liệu, thì các tiêu chí nghiêm ngặt hơn về sự chồng chéo của Lambda có thể mạnh mẽ hơn.

Một lần nữa, tôi không phải là một chuyên gia trong những vấn đề này, vì vậy tôi vẫn hy vọng rằng ai đó có nhiều kinh nghiệm hơn có thể thêm vào lời giải thích này.

Tài liệu tham khảo:

Beckers, Jean-Marie và M. Rixen. "Tính toán EOF và điền dữ liệu từ bộ dữ liệu hải dương học chưa hoàn chỉnh." Tạp chí Công nghệ Khí quyển và Đại dương 20.12 (2003): 1839-1856.

Overland, J. và R. Preisendorfer, Một thử nghiệm quan trọng đối với các thành phần chính được áp dụng cho khí hậu lốc xoáy, Mon. Dệt. Rev, 110, 1-4, 1982.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.