Das ist eine lange Antwort . Lassen Sie uns hier eine Kurzgeschichtenversion davon geben.
- Es gibt keine gute algebraische Lösung für dieses Problem, also brauchen wir einen numerischen Algorithmus.
- Die Funktion hat viele schöne Eigenschaften. Wir können diese nutzen, um eine spezialisierte Version von Newtons Methode für dieses Problem mit garantierter monotoner Konvergenz für jede Wurzel zu erstellen .df(λ)
- Sogar gehirntoter
R
Code ohne Optimierungsversuche kann in wenigen Sekunden ein Raster der Größe 100 mit 100.000 berechnen . Sorgfältig geschriebener Code würde dies um mindestens 2–3 Größenordnungen reduzieren.p=100000C
Im Folgenden werden zwei Schemata angegeben, um eine monotone Konvergenz zu gewährleisten. Man verwendet die unten gezeigten Grenzen, die gelegentlich helfen, ein oder zwei Newton-Schritte zu sparen.
Beispiel : und ein einheitliches Gitter für die Freiheitsgrade der Größe 100. Die Eigenwerte sind paretoverteilt und daher stark verzerrt. Unten finden Sie Tabellen mit der Anzahl der Newton-Schritte, um die einzelnen Wurzeln zu finden.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
Es wird im Allgemeinen keine geschlossene Lösung dafür geben , aber es ist eine Menge Struktur vorhanden, die verwendet werden kann, um sehr effektive und sichere Lösungen unter Verwendung von Standardmethoden zum Auffinden von Wurzeln zu erzeugen.
Bevor wir uns zu sehr mit Dingen , wollen wir einige Eigenschaften und Konsequenzen der Funktion
df(λ)=∑i=1pd2id2i+λ.
Eigenschaft 0 : ist eine rationale Funktion von . (Dies geht aus der Definition hervor.)
Konsequenz 0 : Es gibt keine allgemeine algebraische Lösung zum Finden der Wurzel . Dies liegt daran, dass es ein äquivalentes Polynomwurzelfindungsproblem des Grades Wenn also nicht extrem klein ist (dh weniger als fünf), gibt es keine allgemeine Lösung. Wir brauchen also eine numerische Methode. λ d f ( λ ) - y = 0 p pdfλ
df(λ)−y=0pp
Eigenschaft 1 : Die Funktion ist konvex und nimmt bei . (Nehmen Sie Derivate.)
Konsequenz 1 (a) : Newtons Algorithmus zum Auffinden von Wurzeln wird sich in dieser Situation sehr gut verhalten . Sei die gewünschten Freiheitsgrade und die entsprechende Wurzel, dh . Insbesondere wenn wir mit einem Anfangswert (also ) beginnen, konvergiert die Folge von Newton-Schritt-Iterationen monoton gegen einzigartige Lösung λ ≥ 0 y λ 0 y = d f ( λ 0 ) λ 1 < λ 0 d f ( λ 1 ) > y λ 1 , λ 2 , … λ 0 λ 1 > λ 0 λ 2 ≤ λ 0 d f d f λ d f y 1 y 2 < ydfλ≥0
yλ0y=df(λ0)λ1<λ0df(λ1)>yλ1,λ2,…λ0 .
Konsequenz 1 (b) : Wenn wir mit , würde der erste Schritt , von wo aus er sich durch die vorherige Konsequenz monoton zur Lösung erhöht (siehe Warnung) unten). Intuitiv folgt diese letzte Tatsache, denn wenn wir rechts von der Wurzel beginnen, ist die Ableitung aufgrund der Konvexität von "zu" flach, und so führt uns der erste Newton-Schritt irgendwo links von der Wurzel. NB Da ist nicht im allgemeinen konvexen für negativeλ1>λ0λ2≤λ0dfdfλDies ist ein wichtiger Grund, lieber links von der gewünschten Wurzel zu beginnen. Andernfalls müssen wir noch einmal überprüfen, ob der Newton-Schritt zu keinem negativen Wert für die geschätzte Wurzel geführt hat, was dazu führen kann, dass wir uns irgendwo in einem nicht konvexen Teil von .
Konsequenz 1 (c) : Sobald wir die Wurzel für ein und dann von einem nach der Wurzel suchen , verwenden wir so dass unsere anfängliche Vermutung ist das links von der zweiten Wurzel. Somit ist unsere Konvergenz von dort aus garantiert monoton.df
y1λ 1 d f ( λ 1 ) = y 1y2<y1λ1df(λ1)=y1
Eigenschaft 2 : Es gibt vernünftige Grenzen, um "sichere" Startpunkte zu geben. Unter Verwendung von Konvexitätsargumenten und Jensens Ungleichung ergeben sich folgende Grenzen:
Consequence 2 : Dies sagt uns , dass die Wurzel erfüllt gehorcht
Wir haben also bis auf eine gemeinsame Konstante die Wurzel zwischen dem harmonischen und dem arithmetischen Mittel von eingeklemmt .λ 0 d f ( λ 0 ) = y 1
p1+λp∑d−2i≤df(λ)≤p∑id2i∑id2i+pλ.
λ0df(λ0)=yd 2 i11p∑id−2i(p−yy)≤λ0≤(1p∑id2i)(p−yy).(⋆)
d2i
Dies setzt voraus, dass für alle . Ist dies nicht der Fall, so gilt dieselbe Schranke, indem nur das positive und durch die Anzahl des positiven . Anmerkung : Da Annahme von , ist , von wo aus die Grenzen immer nichttrivial sind (z. B. ist die untere Grenze immer nichtnegativ).i d i p d i d f ( 0 ) = p d i > 0 y ∈ ( 0 , p ]di>0idipdidf(0)=pdi>0y∈(0,p]
Hier ist eine Darstellung eines "typischen" Beispiels für mit . Für die Freiheitsgrade haben wir ein Raster der Größe 10 eingeblendet. Dies sind die horizontalen Linien im Plot. Die vertikalen grünen Linien entsprechen der unteren Grenze in .p = 400 ( ⋆ )df(λ)p=400(⋆)
Ein Algorithmus und ein Beispiel für einen R-Code
Ein sehr effizienter Algorithmus, der ein Gitter gewünschter Freiheitsgrade in besteht darin, sie in absteigender Reihenfolge zu sortieren und dann nacheinander die Wurzel von jedem zu finden, wobei die vorherige Wurzel als Ausgangspunkt für die folgenden verwendet wird Wir können dies weiter verfeinern, indem wir prüfen, ob jede Wurzel größer als die Untergrenze für die nächste Wurzel ist, und wenn nicht, können wir die nächste Iteration stattdessen an der Untergrenze beginnen. ( 0 , p ]y1,…yn(0,p]
Hier ist ein Beispielcode, in dem R
keine Optimierungsversuche unternommen wurden. Wie unten zu sehen, ist es immer noch ziemlich schnell, obwohl R
es - höflich ausgedrückt - entsetzlich, schrecklich, schrecklich langsam in Schleifen ist.
# 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)))
}
Unten ist der endgültige vollständige Algorithmus, der ein Gitter von Punkten und einen Vektor von ( nicht !) .d 2 idi 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
}
Beispiel Funktionsaufruf
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)