Как определить важные основные компоненты, используя метод начальной загрузки или метод Монте-Карло?

40

Я заинтересован в определении количества значимых паттернов, вытекающих из анализа основных компонентов (PCA) или анализа эмпирических ортогональных функций (EOF). Я особенно заинтересован в применении этого метода к климатическим данным. Поле данных представляет собой матрицу MxN, где М - это измерение времени (например, дни), а N - пространственное измерение (например, положения в долготе / широте). Я читал о возможном методе начальной загрузки для определения значимых ПК, но не смог найти более подробное описание. До сих пор я применял «Правило большого пальца Норта» (North et al ., 1982), чтобы определить это ограничение, но мне было интересно, доступен ли более надежный метод.

В качестве примера:

###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="")

введите описание изображения здесь

И вот метод, который я использовал для определения значимости ПК. Основное правило заключается в том, что разница между соседними лямбдами должна быть больше, чем связанная с ними ошибка.

###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)

введите описание изображения здесь

Я посчитал полезным раздел главы Björnsson and Venegas ( 1997 ) о значимых тестах - они относятся к трем категориям тестов, из которых, вероятно, я надеюсь использовать доминирующий тип дисперсии . Относится к типу подхода Монте-Карло, в котором тасуется измерение времени и пересчитывается лямбда-многовариант по многим перестановкам. von Storch и Zweiers (1999) также ссылаются на тест, который сравнивает лямбда-спектр с эталонным спектром «шума». В обоих случаях я немного не уверен в том, как это можно сделать, а также в том, как проводится тест значимости с учетом доверительных интервалов, определенных перестановками.

Спасибо за вашу помощь.

Ссылки: Бьорнссон, Х. и Венегас, С.А. (1997). «Руководство по EOF и SVD анализу климатических данных», Университет Макгилла, Отчет CCGCR № 97-1, Montréal, Québec, 52pp. http://andvari.vedur.is/%7Efolk/halldor/PICKUP/eof.pdf

GR North, TL Bell, RF Cahalan и FJ Moeng. (1982). Ошибки выборки при оценке эмпирических ортогональных функций. ПН Wea. Rev., 110: 699–706.

фон Шторх, H, Цвайерс, FW (1999). Статистический анализ в исследовании климата. Издательство Кембриджского университета.

Марк в коробке
источник
Как вы относитесь к подходу начальной загрузки?
Майкл Р. Черник
4
Бутстрап здесь не сработает. Это не будет работать с наборами данных, в которых почти каждое наблюдение коррелирует с почти любым другим наблюдением; ему нужна независимость или, по крайней мере, приблизительная независимость (скажем, условия смешивания во временных рядах) для получения оправданных копий данных. Конечно, существуют специальные схемы начальной загрузки, такие как дикая начальной загрузки, которые могут обойти эти проблемы. Но я не буду много ставить на это. И вам действительно нужно смотреть на многомерные статистические книги и следить за ними, чтобы не получить еще одну неоправданную хоккейную клюшку в качестве ответа.
StasK
2
@Marc в поле, которое вы можете использовать для различных загрузочных блоков блоков, которые используются для временных рядов, MBB (загрузочный блок движущихся блоков), CBB (загрузочный блок круглых блоков) или SBB (загрузочный блок стационарных блоков), которые используют временные блоки данных для оценки модели. параметры.
Майкл Р. Черник
3
@StasK Я не знаю, почему вы думаете, что вам нужны условия смешивания для применения начальной загрузки к временным рядам. Методы, основанные на модели, просто требуют, чтобы вы подгоняли структуру временного ряда, а затем вы можете загрузить остатки. Таким образом, вы можете иметь временные ряды с трендами и сезонными компонентами, и при этом выполнять загрузку на основе моделей.
Майкл Р. Черник
2
У меня нет доступа к полному тексту, но вы можете попытаться взглянуть: «Хамид Бабаморади, Франс ван ден Берг, Осмунд Риннан, основанные на Bootstrap пределы доверия в анализе основных компонентов - пример из практики, Chemometrics and Intelligent Laboratory Systems, Volume 120, 15 января 2013 г., страницы 97-105, ISSN 0169-7439, 10.1016 / j.chemolab.2012.10.007. ( Sciencedirect.com/science/article/pii/S0169743912002171 ) Ключевые слова: Bootstrap; PCA; доверительные пределы; BC < sub> a </ sub>; Неопределенность "
tomasz74

Ответы:

19

Я собираюсь немного продвинуть диалог, хотя это мой вопрос. Прошло 6 месяцев с тех пор, как я спросил об этом, и, к сожалению, не было дано полных ответов, я постараюсь обобщить то, что я собрал до сих пор, и посмотрим, сможет ли кто-нибудь уточнить оставшиеся вопросы. Пожалуйста, извините за длинный ответ, но я не вижу другого пути ...

Сначала я продемонстрирую несколько подходов, использующих возможно лучший синтетический набор данных. Это взято из статьи Беккерса и Риксона ( 2003 ), иллюстрирующей использование алгоритма для проведения EOF на gappy данных. Я воспроизвел алгоритм на R, если кому-то интересно ( ссылка ).

Синтетический набор данных:

#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))

введите описание изображения здесь

Итак, поле истинных данных Xtсостоит из 9 сигналов, и я добавил к нему некоторый шум, чтобы создать наблюдаемое поле Xp, которое будет использовано в примерах ниже. EOF определяются как таковые:

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

Следуя примеру, который я использовал в своем первоначальном примере, я буду определять «значимые» EOFs по эмпирическому правилу.

Правило Севера

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)

введите описание изображения здесь

Поскольку лямбда-значения 2: 4 очень близки друг к другу по амплитуде, они считаются незначительными по эмпирическому правилу - то есть их соответствующие EOF-шаблоны могут перекрываться и смешиваться, учитывая их аналогичные амплитуды. Это прискорбно, учитывая, что мы знаем, что в поле действительно существует 9 сигналов.

Более субъективный подход состоит в том, чтобы просмотреть преобразованные в лог значения Lambda («график Scree») и затем подогнать регрессию к конечным значениям. Затем можно визуально определить, на каком уровне лямбда-значения лежат выше этой линии:

Сюжетный сюжет

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)

введите описание изображения здесь

Итак, 5 ведущих EOF лежат выше этой линии. Я пробовал этот пример, когда Xpне было добавлено никакого дополнительного шума, и результаты показывают все 9 исходных сигналов. Итак, незначительность EOFs 6: 9 связана с тем, что их амплитуда ниже, чем шум в поле.

Более объективный метод - критерии «Правила N» по Overland и Preisendorfer (1982). В wqпакете есть реализация , которую я покажу ниже.

Правило 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)

введите описание изображения здесь

Правило N идентифицировало 4 значимых EOF. Лично мне нужно лучше понять этот метод; Почему можно измерить уровень ошибки на основе случайного поля, которое не использует такое же распределение, как в Xp? Одним из вариантов этого метода будет повторная выборка данных, Xpчтобы каждый столбец переставлялся случайным образом. Таким образом, мы гарантируем, что полная дисперсия случайного поля равна Xp. Повторная выборка много раз позволяет нам вычислить базовую ошибку разложения.

Монте-Карло со случайным полем (т.е. сравнение нулевой модели)

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)

введите описание изображения здесь

Опять же, 4 EOF выше распределений для случайных полей. Я обеспокоен этим подходом и правилом N в том, что они не относятся к доверительным интервалам значений лямбда; Например, высокое первое лямбда-значение автоматически приведет к меньшему количеству отклонений, которые будут объясняться концевыми. Таким образом, лямбда, рассчитанная по случайным полям, всегда будет иметь менее крутой наклон и может привести к выбору слишком небольшого количества значимых EOF. [ПРИМЕЧАНИЕ: eofNum()функция предполагает, что EOF рассчитываются по корреляционной матрице. Это число может отличаться, если используется, например, ковариационная матрица (центрированные, но не масштабированные данные).]

Наконец, @ tomasz74 упомянул статью Babamoradi et al. (2013), который я кратко рассмотрел. Это очень интересно, но, кажется, больше сосредоточено на расчете КИ нагрузок и коэффициентов EOF, а не на лямбду. Тем не менее, я считаю, что это может быть принято для оценки лямбда-ошибки с использованием той же методологии. Начальная выборка выполняется для поля данных путем повторной выборки строк, пока не будет создано новое поле. Одну и ту же строку можно пересчитать более одного раза, что является непараметрическим подходом, и нет необходимости делать предположения о распределении данных.

Начальная загрузка лямбда-значений

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)

введите описание изображения здесь

Хотя это может быть более надежным, чем эмпирическое правило Норда, для расчета погрешности значений лямбда, теперь я считаю, что вопрос о значении EOF сводится к различным мнениям о том, что это значит. Для эмпирических правил и методов начальной загрузки Севера значение, по-видимому, больше зависит от того, перекрывается ли значение лямбда или нет. Если есть, то эти EOF могут смешиваться в своих сигналах и не представлять «истинные» шаблоны. С другой стороны, эти два EOF могут описывать значительную дисперсию (по сравнению с разложением случайного поля - например, Правило N). Поэтому, если кто-то заинтересован в фильтрации шума (т. Е. Через усечение EOF), тогда будет достаточно правило N. Если кто-то заинтересован в определении реальных шаблонов в наборе данных, то более строгие критерии лямбда-перекрытия могут быть более надежными.

Опять же, я не эксперт в этих вопросах, поэтому я все еще надеюсь, что кто-то с большим опытом может добавить к этому объяснению.

Ссылки:

Беккерс, Жан-Мари и М. Риксен. «Расчеты EOF и заполнение данных из неполных наборов океанографических данных». Журнал атмосферных и океанических технологий 20.12 (2003): 1839-1856.

Overland, J., R. Preisendorfer, Тест значимости для основных компонентов, применяемых в циклонической климатологии, пн. Wea. Rev., 110, 1-4, 1982.

Марк в коробке
источник