Esta é uma resposta longa . Então, vamos dar uma versão resumida dela aqui.
- Não há uma boa solução algébrica para esse problema de busca de raiz, por isso precisamos de um algoritmo numérico.
- A função possui muitas propriedades agradáveis. Podemos utilizá-los para criar uma versão especializada do método de Newton para esse problema, com convergência monotônica garantida para cada raiz.df(λ)
- Mesmo o
R
código de morte encefálica, ausente de qualquer tentativa de otimização, pode calcular uma grade de tamanho 100 com em alguns segundos. Umcódigocuidadosamente escritoreduziria isso em pelo menos 2 a 3 ordens de magnitude.p=100000C
Existem dois esquemas abaixo para garantir a convergência monotônica. Um usa os limites mostrados abaixo, que parecem ajudar a salvar um ou dois passos de Newton ocasionalmente.
Exemplo : e uma grade uniforme para os graus de liberdade de tamanho 100. Os valores próprios são distribuídos por Pareto e, portanto, altamente distorcidos. Abaixo estão as tabelas do número de etapas de Newton para encontrar cada raiz.p=100000
# Table of Newton iterations per root.
# Without using lower-bound check.
1 3 4 5 6
1 28 65 5 1
# Table with lower-bound check.
1 2 3
1 14 85
Não haverá uma solução em forma fechada para esta , em geral, mas não é muito de estrutura presente, que pode ser usado para produzir soluções muito eficazes e seguros, utilizando métodos de determinação de raiz padrão.
Antes de aprofundar as coisas, vamos coletar algumas propriedades e conseqüências da função
df(λ)=∑i=1pd2id2i+λ.
Propriedade 0 : é uma função racional de . (Isso é aparente na definição.)
Consequência 0 : Nenhuma solução algébrica geral existirá para encontrar a raiz . Isso ocorre porque existe um problema equivalente de busca de raiz polinomial de grau e, portanto, se não for extremamente pequeno (ou seja, menor que cinco), nenhuma solução geral existirá. Então, precisaremos de um método numérico.dfλ
df(λ)−y=0pp
Propriedade 1 : a função é convexa e diminui em . (Pegue derivadas.)
Consequência 1 (a) : O algoritmo de busca de raiz de Newton se comportará muito bem nessa situação. Seja os graus de liberdade desejados e a raiz correspondente, ou seja, . Em particular, se começarmos com qualquer valor inicial (então, ), a sequência de iterações da etapa Newton convergirá monotonicamente para o solução únicadfλ≥0
yλ0y=df(λ0)λ1<λ0df(λ1)>yλ1,λ2,…λ0 .
Consequência 1 (b) : Além disso, se com , o primeiro passo renderia , de onde aumentará monotonicamente para a solução pela consequência anterior (consulte a advertência abaixo). Intuitivamente, esse último fato se segue porque, se começarmos à direita da raiz, a derivada é "rasa" demais devido à convexidade de e, portanto, o primeiro passo de Newton nos levará a algum lugar à esquerda da raiz. NB Como d f não éλ1>λ0λ2≤λ0dfdf geralmente convexo para λ negativoλ, isso fornece um forte motivo para preferir começar à esquerda da raiz desejada. Caso contrário, precisamos verificar novamente se o passo de Newton não resultou em um valor negativo para a raiz estimada, o que pode nos colocar em algum lugar em uma porção não-convexa de .
Consequência 1 (c) : depois de encontrarmos a raiz para alguns y 1 e, em seguida, procurarmos a raiz de alguns , usandodf
y1y2<y1λ1 modo que como nosso palpite inicial garante que começamos à esquerda da segunda raiz. Portanto, nossa convergência é garantida para ser monotônica a partir daí.df(λ1)=y1
Propriedade 2 : Existem limites razoáveis para fornecer pontos de partida "seguros". Usando argumentos de convexidade e desigualdade de Jensen, temos os seguintes limites
Consequência 2 : Isso nos diz que a raiz satisfazendo obedece
1
p1+λp∑d−2i≤df(λ)≤p∑id2i∑id2i+pλ.
d f ( λ 0 ) = yλ0df(λ0)=y
Assim, até uma constante comum, imprensamos a raiz entre os meios harmônicos e aritméticos do
d 2 i .
11p∑Eud- 2Eu( p - yy) ≤ λ0 0≤ ( 1p∑Eud2Eu) ( p - yy).( ⋆ )
d2Eu
Isso pressupõe que para todos i . Se este não for o caso, então o mesmo limite detém por considerar unicamente o positivo d i e substituindo p pelo número de positiva d i . NB : Como d f ( 0 ) = p assumindo todos os d idEu> 0EudEupdEud f( 0 ) = p , então y ∈ ( 0 , p ] , de onde os limites são sempre não triviais (por exemplo, o limite inferior é sempre não negativo).dEu> 0y∈(0,p]
Aqui está um gráfico de um exemplo "típico" de com p = 400 . Sobrepusemos uma grade de tamanho 10 aos graus de liberdade. Estas são as linhas horizontais no gráfico. As linhas verdes verticais correspondem ao limite inferior em ( ⋆ ) .df(λ)p=400(⋆)
Um algoritmo e algum exemplo de código R
Um algoritmo muito eficiente, dada uma grade dos graus de liberdade desejados em ( 0 , p ], é classificá-los em ordem decrescente e, em seguida,encontrarsequencialmentea raiz de cada um, usando a raiz anterior como ponto de partida para o Podemos refinar isso ainda mais, verificando se cada raiz é maior que o limite inferior para a próxima raiz e, se não, podemos iniciar a próxima iteração no limite inferior.y1,…yn(0,p]
Aqui está um exemplo de código R
, sem nenhuma tentativa de otimizá-lo. Como visto abaixo, ainda é bastante rápido, embora R
seja - para ser educado - horrivelmente, terrivelmente, terrivelmente lento nos loops.
# Newton's step for finding solutions to regularization dof.
dof <- function(lambda, d) { sum(1/(1+lambda / (d[d>0])^2)) }
dof.prime <- function(lambda, d) { -sum(1/(d[d>0]+lambda / d[d>0])^2) }
newton.step <- function(lambda, y, d)
{ lambda - (dof(lambda,d)-y)/dof.prime(lambda,d) }
# Full Newton step; Finds the root of y = dof(lambda, d).
newton <- function(y, d, lambda = NA, tol=1e-10, smart.start=T)
{
if( is.na(lambda) || smart.start )
lambda <- max(ifelse(is.na(lambda),0,lambda), (sum(d>0)/y-1)/mean(1/(d[d>0])^2))
iter <- 0
yn <- Inf
while( abs(y-yn) > tol )
{
lambda <- max(0, newton.step(lambda, y, d)) # max = pedantically safe
yn <- dof(lambda,d)
iter = iter + 1
}
return(list(lambda=lambda, dof=y, iter=iter, err=abs(y-yn)))
}
Abaixo está o algoritmo completo final, que recebe uma grade de pontos e um vetor de ( não d 2 i !).di d2i
newton.grid <- function(ygrid, d, lambda=NA, tol=1e-10, smart.start=TRUE)
{
p <- sum(d>0)
if( any(d < 0) || all(d==0) || any(ygrid > p)
|| any(ygrid <= 0) || (!is.na(lambda) && lambda < 0) )
stop("Don't try to fool me. That's not nice. Give me valid inputs, please.")
ygrid <- sort(ygrid, decreasing=TRUE)
out <- data.frame()
lambda <- NA
for(y in ygrid)
{
out <- rbind(out, newton(y,d,lambda, smart.start=smart.start))
lambda <- out$lambda[nrow(out)]
}
out
}
Exemplo de chamada de função
set.seed(17)
p <- 100000
d <- sqrt(sort(exp(rexp(p, 10)),decr=T))
ygrid <- p*(1:100)/100
# Should take ten seconds or so.
out <- newton.grid(ygrid,d)