Esta es una respuesta larga . Entonces, demos una versión de cuento corto aquí.
- No hay una buena solución algebraica para este problema de búsqueda de raíces, por lo que necesitamos un algoritmo numérico.
- La función tiene muchas propiedades agradables. Podemos aprovecharlos para crear una versión especializada del método de Newton para este problema con convergencia monotónica garantizada a cada raíz.df(λ)
- Incluso el
R
código con muerte cerebral sin ningún intento de optimización puede calcular una cuadrícula de tamaño 100 con en unos pocos segundos. Uncódigoescrito cuidadosamentereduciría esto en al menos 2–3 órdenes de magnitud.p=100000C
A continuación se detallan dos esquemas para garantizar la convergencia monotónica. Uno usa los límites que se muestran a continuación, que parecen ayudar a salvar un paso de Newton o dos en ocasiones.
Ejemplo : y una cuadrícula uniforme para los grados de libertad de tamaño 100. Los valores propios están distribuidos por Pareto, por lo tanto, muy sesgados. A continuación hay tablas de la cantidad de pasos de Newton para encontrar cada raíz.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
No habrá una solución de forma cerrada para este , en general, pero no es una gran cantidad de estructura actual que se puede utilizar para producir soluciones muy eficaces y seguros utilizando métodos de búsqueda de raíz estándar.
Antes de profundizar demasiado en las cosas, recopilemos algunas propiedades y consecuencias de la función
df(λ)=∑i=1pd2id2i+λ.
Propiedad 0 : es una función racional de λ . (Esto es evidente a partir de la definición).
Consecuencia 0 : No existirá una solución algebraica general para encontrar la raíz d f ( λ ) - y = 0 . Esto se debe a que existe un problema equivalente de búsqueda de raíces polinomiales de grado p, por lo que si p no es extremadamente pequeño (es decir, menos de cinco), no existirá una solución general. Entonces, necesitaremos un método numérico.dfλ
df(λ)−y=0pp
Propiedad 1 : La función es convexa y disminuye en λ ≥ 0 . (Tome derivados.)
Consecuencia 1 (a) : el algoritmo de búsqueda de raíces de Newton se comportará muy bien en esta situación. Sean y los grados de libertad deseados y λ 0 la raíz correspondiente, es decir, y = d f ( λ 0 ) . En particular, si comenzamos con cualquier valor inicial λ 1 < λ 0 (entonces, d f ( λ 1dfλ≥0
yλ0y=df(λ0)λ1<λ0 ), entonces la secuencia de iteraciones de Newton-paso λ 1 , λ 2 , ... convergerámonotónicamentea la solución única λ 0 .
Consecuencia 1 (b): Además, si comenzáramos con λ 1 > λ 0 , entonces elprimerpaso produciría λ 2 ≤ λ 0df(λ1)>yλ1,λ2,…λ0
λ1>λ0λ2≤λ0, de donde se incrementará monotónicamente a la solución por la consecuencia previa (ver advertencia más abajo). Intuitivamente, este último hecho es consecuencia de que si nos ponemos a la derecha de la raíz, la derivada es "demasiado" superficial debido a la convexidad de por lo que el primer paso Newton nos llevará algún lugar a la izquierda de la raíz. Nota: dado que d f no es en general convexo para λ negativo , esto proporciona una fuerte razón para preferir comenzar a la izquierda de la raíz deseada. De lo contrario, debemos verificar que el paso de Newton no haya resultado en un valor negativo para la raíz estimada, lo que puede colocarnos en algún lugar en una porción no convexa de d f .
dfdfλdf
Consecuencia 1 (c) : una vez que hemos encontrado la raíz de algunos y estamos buscando la raíz de algunos y 2 < y 1 , usamos λ 1 tal que d f ( λ 1 ) = y 1 como nuestra suposición inicial garantiza que comenzamos a la izquierda de la segunda raíz. Entonces, nuestra convergencia está garantizada para ser monótona a partir de ahí.y1y2<y1λ1df(λ1)=y1
Propiedad 2 : existen límites razonables para proporcionar puntos de partida "seguros". Usando argumentos de convexidad y la desigualdad de Jensen, tenemos los siguientes límites
Consecuencia 2: Esto nos dice que la raíz λ 0 satisface d f ( λ 0 ) = y obedece a
1
p1+λp∑d−2i≤df(λ)≤p∑id2i∑id2i+pλ.
λ0df(λ0)=y
Entonces, hasta una constante común, hemos intercalado la raíz entre los medios armónicos y aritméticos de
d 2 i .
11p∑id−2i(p−yy)≤λ0≤(1p∑id2i)(p−yy).(⋆)
d2i
Esto supone que para todo i . Si este no es el caso, entonces el mismo límite se mantiene considerando solo el d i positivo y reemplazando p por el número de d i positivo . NB : Dado que d f ( 0 ) = p asumiendo todos d i > 0 , entonces y ∈ ( 0 , p ] , de donde los límites son siempre no triviales (por ejemplo, el límite inferior siempre no es negativo).di>0idipdidf(0)=pdi>0y∈(0,p]
Aquí hay una gráfica de un ejemplo "típico" de con p = 400 . Hemos superpuesto una cuadrícula de tamaño 10 para los grados de libertad. Estas son las líneas horizontales en la trama. Las líneas verdes verticales corresponden al límite inferior en ( ⋆ ) .df(λ)p=400(⋆)
Un algoritmo y algún código R de ejemplo
Un algoritmo muy eficiente dado una grilla de grados de libertad deseados en ( 0 , p ] es ordenarlos en orden decreciente y luego encontrar secuencialmente la raíz de cada uno, utilizando la raíz anterior como punto de partida para el siguiente. Podemos refinar esto aún más comprobando si cada raíz es mayor que el límite inferior para la siguiente raíz y, si no, podemos comenzar la siguiente iteración en el límite inferior.y1,…yn(0,p]
Aquí hay un código de ejemplo R
, sin intentos de optimizarlo. Como se ve a continuación, todavía es bastante rápido, aunque R
es, por decirlo cortésmente, horriblemente, terriblemente, muy lento en los bucles.
# 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)))
}
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
}
Llamada de función de muestra
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)