La risposta piuttosto anti-climatica a " Qualcuno sa perché questo è? " È che a nessuno importa abbastanza per implementare una routine di regressione della cresta non negativa. Uno dei motivi principali è che le persone hanno già iniziato a implementare
routine di reti elastiche non negative (ad esempio qui e qui ). La rete elastica include la regressione della cresta come un caso speciale (uno essenzialmente imposta la parte LASSO per avere una ponderazione zero). Queste opere sono relativamente nuove, quindi non sono ancora state incorporate in scikit-learn o in un simile pacchetto di uso generale. Potresti chiedere informazioni agli autori di questi articoli per il codice.
MODIFICARE:
Come @amoeba ed io abbiamo discusso sui commenti, l'implementazione effettiva di questo è relativamente semplice. Supponiamo che uno abbia il seguente problema di regressione a:
y=2x1−x2+ϵ,ϵ∼N(0,0.22)
dove e sono entrambi normali standard come: . Si noti che utilizzo variabili predittive standardizzate, quindi non è necessario normalizzarle in seguito. Per semplicità non includo neanche un'intercettazione. Possiamo risolvere immediatamente questo problema di regressione usando la regressione lineare standard. Quindi in R dovrebbe essere qualcosa del genere:x 2 x p ∼ N ( 0 , 1 )x1x2xp∼N(0,1)
rm(list = ls());
library(MASS);
set.seed(123);
N = 1e6;
x1 = rnorm(N)
x2 = rnorm(N)
y = 2 * x1 - 1 * x2 + rnorm(N,sd = 0.2)
simpleLR = lm(y ~ -1 + x1 + x2 )
matrixX = model.matrix(simpleLR); # This is close to standardised
vectorY = y
all.equal(coef(simpleLR), qr.solve(matrixX, vectorY), tolerance = 1e-7) # TRUE
Nota l'ultima riga. Quasi tutte le routine di regressione lineare utilizzano la decomposizione QR per stimare . Vorremmo usare lo stesso per il nostro problema di regressione della cresta. A questo punto leggi questo post di @whuber; implementeremo esattamente questa procedura. In breve, aumenteremo la nostra matrice di design originale con una matrice diagonale e il nostro vettore di risposta con zeri . In questo modo saremo in grado di riesprimere il problema di regressione della cresta originale as dove ilX √βXyp(XTX+λI) - 1 XTy( ˉ X T ˉ X ) - 1 ˉ X T ˉ y ¯λ−−√Ipyp(XTX+λI)−1XTy(X¯TX¯)−1X¯Ty¯¯simboleggia la versione aumentata. Dai un'occhiata alle diapositive 18-19 anche da queste note per completezza, le ho trovate abbastanza semplici. Quindi in R vorremmo alcuni come segue:
myLambda = 100;
simpleRR = lm.ridge(y ~ -1 + x1 + x2, lambda = myLambda)
newVecY = c(vectorY, rep(0, 2))
newMatX = rbind(matrixX, sqrt(myLambda) * diag(2))
all.equal(coef(simpleRR), qr.solve(newMatX, newVecY), tolerance = 1e-7) # TRUE
e funziona. OK, quindi abbiamo ottenuto la parte di regressione della cresta. Potremmo risolvere in un altro modo, tuttavia, potremmo formularlo come un problema di ottimizzazione in cui la somma residua dei quadrati è la funzione di costo e quindi ottimizzare contro di essa, vale a dire. . Abbastanza sicuro possiamo farlo:minβ||y¯−X¯β||22
myRSS <- function(X,y,b){ return( sum( (y - X%*%b)^2 ) ) }
bfgsOptim = optim(myRSS, par = c(1,1), X = newMatX, y= newVecY,
method = 'L-BFGS-B')
all.equal(coef(simpleRR), bfgsOptim$par, check.attributes = FALSE,
tolerance = 1e-7) # TRUE
che come previsto funziona di nuovo. Quindi ora vogliamo solo: dove . Che è semplicemente lo stesso problema di ottimizzazione ma vincolato in modo che la soluzione non sia negativa.minβ||y¯−X¯β||22β≥0
bfgsOptimConst = optim(myRSS, par = c(1,1), X=newMatX, y= newVecY,
method = 'L-BFGS-B', lower = c(0,0))
all(bfgsOptimConst$par >=0) # TRUE
(bfgsOptimConst$par) # 2.000504 0.000000
che mostra che l'attività di regressione della cresta non negativa originale può essere risolta riformulandosi come un semplice problema di ottimizzazione vincolata. Alcuni avvertimenti:
- Ho usato (praticamente) variabili predittive normalizzate. Dovrai rendere conto della normalizzazione da solo.
- La stessa cosa vale per la non normalizzazione dell'intercetta.
- Ho usato
optim
's L-BFGS-B argomento. È il solutore R più vaniglia che accetta limiti. Sono sicuro che troverai decine di risolutori migliori.
- In generale, i problemi dei minimi quadrati lineari sono posti come attività di ottimizzazione quadratica . Questo è un eccessivo per questo post, ma tieni presente che puoi ottenere una migliore velocità se necessario.
- Come menzionato nei commenti, è possibile saltare la regressione della cresta come parte della regressione lineare aumentata e codificare direttamente la funzione di costo della cresta come problema di ottimizzazione. Questo sarebbe molto più semplice e questo post sarà significativamente più piccolo. Per ragioni di argomento, aggiungo anche questa seconda soluzione.
- Non sono completamente conversatore in Python ma essenzialmente puoi replicare questo lavoro usando le funzioni di ottimizzazione di NumPy linalg.solve e SciPy .
- Per scegliere l'iperparametro ecc. Fai semplicemente il solito CV-step che faresti in ogni caso; niente cambia.λ
Codice per il punto 5:
myRidgeRSS <- function(X,y,b, lambda){
return( sum( (y - X%*%b)^2 ) + lambda * sum(b^2) )
}
bfgsOptimConst2 = optim(myRidgeRSS, par = c(1,1), X = matrixX, y = vectorY,
method = 'L-BFGS-B', lower = c(0,0), lambda = myLambda)
all(bfgsOptimConst2$par >0) # TRUE
(bfgsOptimConst2$par) # 2.000504 0.000000