Mise en œuvre de la régression des crêtes: sélectionner une grille intelligente pour

17

J'implémente Ridge Regression dans un module Python / C, et je suis tombé sur ce "petit" problème. L'idée est que je souhaite échantillonner les degrés de liberté effectifs plus ou moins également espacés (comme le graphique de la page 65 sur les "Éléments de l'apprentissage statistique" ), c'est-à-dire, échantillon: où sont les valeurs propres de la matrice , à partir de à \ mathrm {df} (\ lambda _ {\ min}) = p . Un moyen simple de définir la première limite est de laisser \ lambda _ {\ max} = \ sum_i ^ p d_i ^ 2 / c (en supposant \ lambda _ {\ max} \ gg d_i ^ 2 ), où c

df(λ)=i=1pdi2di2+λ,
di2XTXdf(λmax)0df(λmin)=pλmax=ipdi2/cλmaxdi2cest une petite constante et représente approximativement le degré de liberté minimum que vous souhaitez échantillonner (par exemple c=0.1 ). La deuxième limite est bien sûr λmin=0 .

Comme le titre l'indique, j'ai besoin d'échantillonner λ de λmin à λmax à une certaine échelle de telle sorte que df(λ) soit échantillonné (environ), par exemple, dans 0.1 intervalle de c à p ... existe-t-il un moyen facile de le faire? J'ai pensé résoudre l'équation df(λ) pour chaque λ utilisant une méthode de Newton-Raphson, mais cela ajoutera trop d'itérations, spécialement lorsque p est grand. Aucune suggestion?

Néstor
la source
1
Cette fonction est une fonction rationnelle convexe décroissante de λ0 . Les racines, en particulier si elles sont choisies sur une grille dyadique, devraient être très rapides à trouver.
cardinal
@cardinal, vous avez probablement raison. Cependant, si possible, j'aimerais savoir s'il existe une grille "par défaut". Par exemple, j'ai essayé d'obtenir une grille en faisant , où , et fonctionnait assez bien pour certains degrés de liberté, mais comme , il a explosé. Cela m'a fait me demander s'il y avait peut-être une bonne façon de choisir la grille pour les , c'est ce que je demande. Si cela n'existe pas, je serais également heureux de le savoir (car je pourrais laisser la méthode Newton-Rapson joyeusement dans mon code sachant "qu'il n'existe pas de meilleure façon"). λ=log(s)λmax/log(smax)s=(1,2,...,smax)df(λ)pλ
Néstor
Pour avoir une meilleure idée des difficultés potentielles que vous rencontrez, quelles sont les valeurs typiques et les pires cas de ? Y a-t-il quelque chose que vous savez a priori sur la distribution des valeurs propres? p
cardinal
@cardinal, les valeurs typiques de dans mon application seraient comprises entre et , mais je veux que ce soit aussi général que possible. À propos de la distribution des valeurs propres, pas vraiment. est une matrice qui contient des prédicteurs dans ses colonnes, qui ne sont pas toujours orthogonales. p1540X
Néstor
1
Newton-Raphson trouve généralement des racines avec une précision de en à étapes pour et de petites valeurs de ; presque jamais plus de étapes. Pour des valeurs plus importantes, jusqu'à étapes sont parfois nécessaires. Étant donné que chaque étape nécessite des calculs , le montant total du calcul est sans conséquence. En effet, le nombre d'étapes ne semble pas dépendre de si une bonne valeur de départ est choisie (je choisis celle que vous utiliseriez si tous les égaux à leur moyenne). 3 4 p = 40 d f ( λ ) 6 30 O ( p ) p d i101234p=40df(λ)630O(p)pdi
whuber

Réponses:

19

Ceci est une longue réponse . Alors, donnons-en une version courte ici.

  • Il n'y a pas de bonne solution algébrique à ce problème de recherche de racine, nous avons donc besoin d'un algorithme numérique.
  • La fonction a beaucoup de belles propriétés. Nous pouvons les exploiter pour créer une version spécialisée de la méthode de Newton pour ce problème avec une convergence monotone garantie à chaque racine.df(λ)
  • Même un Rcode mort cérébral en l' absence de toute tentative d'optimisation peut calculer une grille de taille 100 avec en quelques secondes. Un code soigneusement rédigé réduirait cela d'au moins 2 à 3 ordres de grandeur.p=100000C

Deux schémas sont donnés ci-dessous pour garantir la convergence monotone. On utilise les limites indiquées ci-dessous, qui semblent aider à enregistrer une étape de Newton ou deux à l'occasion.

Exemple : et une grille uniforme pour les degrés de liberté de taille 100. Les valeurs propres sont Pareto-distribuées, donc fortement asymétriques. Voici les tableaux du nombre d'étapes de Newton pour trouver chaque racine.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 

Il n'y aura pas de solution de forme fermée pour cela , en général, mais il y a beaucoup de structure présente qui peut être utilisée pour produire des solutions très efficaces et sûres en utilisant des méthodes de recherche de racines standard.

Avant de creuser trop profondément dans les choses, collectons quelques propriétés et conséquences de la fonction

df(λ)=i=1pdi2di2+λ.

Propriété 0 : est une fonction rationnelle de . (Cela ressort de la définition.) Conséquence 0 : aucune solution algébrique générale n'existera pour trouver la racine . En effet, il existe un problème de recherche de racines polynomial équivalent de degré et donc si n'est pas extrêmement petit (c'est-à-dire moins de cinq), aucune solution générale n'existera. Nous aurons donc besoin d'une méthode numérique. λdfλ
df(λ)y=0ppp

Propriété 1 : La fonction est convexe et décroissante sur . (Prenez les dérivés.) Conséquence 1 (a) : l'algorithme de recherche de racines de Newton se comportera très bien dans cette situation. Soit les degrés de liberté souhaités et la racine correspondante, c'est-à-dire . En particulier, si nous commençons avec une valeur initiale (donc, ), alors la séquence d'itérations de Newton convergera de façon monotone vers le solution unique λ 0dfλ0
λ 0 y = d f ( λ 0 )yλ0y=df(λ0)λ1<λ0df(λ1)>yλ1,λ2,λ0 .
Conséquence 1 (b) : En outre, si nous , la première étape donnerait , d'où elle augmentera de façon monotone jusqu'à la solution par la conséquence précédente (voir la mise en garde au dessous de). Intuitivement, ce dernier fait suit parce que si nous commençons à droite de la racine, la dérivée est "trop" superficielle en raison de la convexité de et donc la première étape de Newton nous mènera quelque part à gauche de la racine. NB Puisque n'est pas en général convexe pour négatifλ1>λ0λ2λ0dfdfλ, cela fournit une bonne raison de préférer commencer à gauche de la racine souhaitée. Sinon, nous devons vérifier que l'étape de Newton n'a pas donné lieu à une valeur négative pour la racine estimée, ce qui peut nous placer quelque part dans une partie non convexe de . Conséquence 1 (c) : Une fois que nous avons trouvé la racine pour certains et que nous recherchons ensuite la racine à partir de certains , en utilisant telle sorte que comme garantie initiale, nous commençons à la gauche de la deuxième racine. Ainsi, notre convergence est garantie d'être monotone à partir de là.df
y1y2<y1λ1df(λ1)=y1

Propriété 2 : Des limites raisonnables existent pour donner des points de départ "sûrs". En utilisant des arguments de convexité et l'inégalité de Jensen, nous avons les limites suivantes Conséquence 2 : cela nous indique que la racine satisfaisant obéit Donc, jusqu'à une constante commune, nous avons pris en sandwich la racine entre les moyennes harmonique et arithmétique du .

p1+λpdi2df(λ)pidi2idi2+pλ.
λ0df(λ0)=y
()11pidi2(pyy)λ0(1pidi2)(pyy).
di2

Cela suppose que pour tout . Si ce n'est pas le cas, alors la même borne tient en considérant uniquement le positif et en remplaçant par le nombre de positifs . NB : Puisque supposant que tous les , alors , d'où les bornes sont toujours non triviales (par exemple, la borne inférieure est toujours non négative).di>0idipdidf(0)=pdi>0y(0,p]

Voici un tracé d'un exemple "typique" de avec . Nous avons superposé une grille de taille 10 pour les degrés de liberté. Ce sont les lignes horizontales de l'intrigue. Les lignes vertes verticales correspondent à la borne inférieure de .df(λ)p=400()

Exemple de tracé DOF avec grille et bornes

Un algorithme et un exemple de code R

Un algorithme très efficace étant donné une grille de degrés de liberté in consiste à les trier par ordre décroissant puis à trouver séquentiellement la racine de chacun, en utilisant la racine précédente comme point de départ pour les éléments suivants 1. Nous pouvons affiner cela en vérifiant si chaque racine est supérieure à la borne inférieure de la racine suivante, et sinon, nous pouvons commencer l'itération suivante à la borne inférieure à la place.y1,yn(0,p]

Voici un exemple de code R, sans aucune tentative d'optimisation. Comme on le voit ci-dessous, il est encore assez rapide même s'il Rest - pour le dire poliment - horriblement, terriblement, terriblement lent aux boucles.

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

Ci-dessous se trouve l'algorithme complet final qui prend une grille de points, et un vecteur du ( pas !).di di2

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
}

Exemple d'appel de fonction

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)
cardinal
la source
Favorisant la question pour que je puisse me référer à cette réponse. Merci d'avoir publié cette analyse détaillée, cardinal.
Macro
Réponse étonnante :-), merci beaucoup cardinal pour les suggestions ET la réponse.
Néstor
1

De plus, il existe deux méthodes qui permettront de calculer efficacement le chemin de régularisation complet:

  1. GPS
  2. glmnet
  3. gcdnet

Ce qui précède sont tous des packages R, car vous utilisez Python, scikit-learn contient des implémentations pour ridge, lasso et élastique net.

sebp
la source
1
La olsfonction du rmspackage R peut utiliser l'optimisation numérique pour trouver la pénalité optimale à l'aide d'un AIC efficace. Mais il faut prévoir la peine maximale qui n'est pas toujours facile.
Frank Harrell
0

Une alternative possible selon la source ci-dessous semble être:

df(λ)=tr(X(XX+λIp)1X)

(XX+λIp)1λ

Source: https://onlinecourses.science.psu.edu/stat857/node/155

José Bayoán Santiago Calderón
la source