이것은 긴 대답 입니다. 여기에 짧은 이야기 버전을 드리겠습니다.
- 이 근본 찾기 문제에 대한 대수적 해결책은 없으므로 수치 알고리즘이 필요합니다.
- 함수 df(λ) 에는 멋진 속성이 많이 있습니다. 이를 활용 하여 각 루트에 단조 수렴 이 보장되는이 문제에 대한 특수한 버전의 Newton 방법을 만들 수 있습니다 .
R
최적화 시도가없는 뇌사 코드 조차도 p = 100 으로 크기 100의 그리드를 계산할 수 있습니다.몇 초 만 에 000 . 신중하게 작성된코드는 이것을 2-3 배 정도 줄입니다.p=100000C
단조 수렴을 보장하기 위해 아래에 주어진 두 가지 체계가 있습니다. 아래에 표시된 범위를 사용하여 경우에 따라 뉴턴 단계를 저장하는 데 도움이되는 것으로 보입니다.
예 : 크기 고유 값 (100)의 자유도를위한 균일 한 그리드는 따라서 매우 비대칭, 파레토 분포한다. 아래는 각 루트를 찾기위한 뉴턴 단계 수의 표입니다.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
이것에 대한 닫힌 형태의 솔루션이되지 않습니다 일반적으로,하지만 거기에 있다 표준 루트 찾는 방법을 사용하여 매우 효과적이고 안전한 솔루션을 생산하는 데 사용할 수있는 구조가 존재하는 많은.
너무 깊이 파고 들기 전에 함수의 일부 속성과 결과를 수집합시다.
df(λ)=∑i=1pd2id2i+λ.
속성 0 : 는 λ 의 합리적인 함수입니다 . (이 정의로부터 분명하다.)
그 결과 0 없음 일반 대수 용액 루트 발견 존재 없다 차원 F ( λ ) - Y = 0 . 이는 p 의 등가 다항식 근 찾기 문제 가 있기 때문에 p 가 매우 작지 않은 경우 (즉, 5 미만) 일반적인 해결책이 존재하지 않기 때문입니다. 따라서 우리는 수치 적 방법이 필요합니다.dfλ
df(λ)−y=0pp
속성 1 : 기능 는 볼록하고 λ ≥ 0 에서 감소합니다 . (파생 상품을 가져 가라.)
결과 (1) (A)를 : 뉴턴의 루트 찾는 알고리즘이 작동합니다 매우 이 상황에서 잘. y를 원하는 자유 도로하고 λ 0 을 해당 근, 즉 y = d f ( λ 0 )로 하자 . 특히, 함께 시작하면 어떤 초기 값 λ 1 < λ 0 (매우, D F ( λ 1dfλ≥0
yλ0y=df(λ0)λ1<λ0 )이면 뉴턴 단계 반복 시퀀스 λ 1 , λ 2 , … 는고유 한 솔루션 λ 0에 단조롭게수렴됩니다.
결과 1 (b): 우리로 시작한다면 또한, λ 1 > λ 0 후첫단계는 수득 할 λ 2 ≤ λ 0df(λ1)>yλ1,λ2,…λ0
λ1>λ0λ2≤λ0이전 결과에 따라 단조롭게 솔루션으로 증가합니다 (아래주의 사항 참조). 직관적으로,이 마지막 사실은 우리가 루트의 오른쪽에서 시작하면 의 볼록 함으로 인해 미분이 "너무"얕기 때문에 첫 번째 뉴턴 단계는 루트의 왼쪽 어딘가로 이동하기 때문입니다. NB d f 는 음의 λ에 대해 일반적으로 볼록 하지 않기 때문에 원하는 근의 왼쪽에서 시작하는 것을 선호하는 강력한 이유가됩니다. 그렇지 않으면, 뉴턴 단계가 추정 된 루트에 대해 음의 값을 얻지 않았 음을 다시 확인해야합니다. 이로 인해 d f 의 볼록하지 않은 부분이 나타날 수 있습니다 .
dfdfλdf
결과 1 (c) : 우리는 약간의 루트를 발견하면 후 일부에서 루트 검색하는 예 2 < 예 1 사용 λ 1 이되도록 개발 된 F ( λ 1 ) = Y (1) 당초테니까 우리는 두 번째 루트의 왼쪽에서 시작합니다. 따라서 우리의 수렴은 거기에서 단조로운 것으로 보장됩니다.y1y2<y1λ1df(λ1)=y1
속성 2 : "안전한"시작점을 제공하기 위해 합리적인 범위가 존재합니다. 볼록 인수와 젠슨의 불평등을 사용하여, 우리는 다음과 같은 경계가
결과 2:이 루트는 것을 말해 준다 λ 0 만족 차원 F를 ( λ 0 ) = Y 따르는
1
p1+λp∑d−2i≤df(λ)≤p∑id2i∑id2i+pλ.
λ0df(λ0)=y
따라서 공통 상수까지, 우리는
d 2 i 의 고조파와 산술 수단 사이에 뿌리를 끼워 넣었습니다.
11p∑id−2i(p−yy)≤λ0≤(1p∑id2i)(p−yy).(⋆)
d2i
이것은 모든 i에 대해 이라고 가정합니다 . 그렇지 않은 경우, 동일한 결합을 고려하여 보유 만 포지티브 D에게 I를 및 교체 쪽 포지티브 수로 D I . NB : 이후 개발 F ( 0 ) = p는 모든 가정 D를 I > 0 , 다음, Y ∈ ( 0 , P ] 경계가 항상 (사소하다 어디서, 예를 들면, 하한)가 항상 음수이다.di>0idipdidf(0)=pdi>0y∈(0,p]
여기서의 "전형적인"예를 나타내는 도면이다 와 , P = 400 . 우리는 자유도를 위해 크기 10의 격자를 겹쳐 놓았습니다. 이들은 플롯의 수평선입니다. 세로 녹색 선은 ( ⋆ ) 의 하한에 해당합니다 .df(λ)p=400(⋆)
알고리즘 및 일부 예제 R 코드
자유의 원하는 정도의 격자 주어진 매우 효율적인 알고리즘 에서 ( 0 , p는 ] 내림차순으로 정렬하고하는 순차적 의 시작 지점 이전 루트를 이용하여, 각각의 루트를 발견 우리는 각 루트가 다음 루트에 대한 하한보다 큰지 확인하여이를 더 세분화 할 수 있으며, 그렇지 않은 경우에는 하한에서 다음 반복을 시작할 수 있습니다.y1,…yn(0,p]
다음은 코드 R
를 최적화하려는 시도가없는 예제 코드입니다 . 아래에서 볼 수 있듯이, R
공손하게, 공손하게, 끔찍 하게, 루프에서 엄청나게 느리 더라도 여전히 빠릅니다 .
# 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)))
}
다음 격자 점을 얻어 최종 전체 알고리즘과의 벡터이고, ( 되지 거라고 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
}
샘플 함수 호출
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)