Die eher antiklimatische Antwort auf " Weiß jemand, warum das so ist? " Ist, dass sich einfach niemand genug darum kümmert, eine nicht negative Gratregressionsroutine zu implementieren. Einer der Hauptgründe ist, dass die Menschen bereits damit begonnen haben, nicht negative elastische Netzroutinen zu implementieren
(zum Beispiel hier und hier ). Das elastische Netz enthält als Sonderfall die Gratregression (man hat den LASSO-Teil im Wesentlichen so eingestellt, dass er eine Gewichtung von Null hat). Diese Werke sind relativ neu, daher wurden sie noch nicht in scikit-learn oder ein ähnliches Paket für den allgemeinen Gebrauch aufgenommen. Möglicherweise möchten Sie die Autoren dieser Artikel nach Code fragen.
BEARBEITEN:
Wie @amoeba und ich in den Kommentaren besprochen haben, ist die tatsächliche Implementierung relativ einfach. Angenommen, man hat das folgende Regressionsproblem:
y=2x1−x2+ϵ,ϵ∼N(0,0.22)
Dabei sind und beide Standardnormalen wie: . Beachten Sie, dass ich standardisierte Prädiktorvariablen verwende, damit ich mich danach nicht normalisieren muss. Der Einfachheit halber füge ich auch keinen Abschnitt hinzu. Wir können dieses Regressionsproblem sofort mit der linearen Standardregression lösen. In R sollte es also ungefähr so sein: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
Beachten Sie die letzte Zeile. Fast alle linearen Regressionsroutinen verwenden die QR-Zerlegung, um zu schätzen . Wir möchten dasselbe für unser Ridge-Regressionsproblem verwenden. An dieser Stelle lesen Sie diesen Beitrag von @whuber; Wir werden genau dieses Verfahren implementieren . Kurz gesagt, wir werden unsere ursprüngliche Entwurfsmatrix mit einer Diagonalmatrix und unseren Antwortvektor mit Nullen erweitern. Auf diese Weise können wir das ursprüngliche Gratregressionsproblem als erneut ausdrücken wobei derX √βXyp(XTX+λI) - 1 XTy( ˉ X T ˉ X ) - 1 ˉ X T ˉ y ¯λ−−√Ipyp(XTX+λI)−1XTy(X¯TX¯)−1X¯Ty¯¯symbolisiert die erweiterte Version. Überprüfen Sie auch die Folien 18-19 aus diesen Notizen auf Vollständigkeit. Ich fand sie recht einfach. In R möchten wir also Folgendes:
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
und es funktioniert. OK, also haben wir den Ridge-Regressionsteil bekommen. Wir könnten es jedoch auf andere Weise lösen, wir könnten es als Optimierungsproblem formulieren, bei dem die verbleibende Quadratsumme die Kostenfunktion ist, und dann dagegen optimieren, d. H. . Sicher können wir das tun: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
was wie erwartet wieder funktioniert. Jetzt wollen wir nur noch: wobei . Das ist einfach das gleiche Optimierungsproblem, aber eingeschränkt, so dass die Lösung nicht negativ ist. β≥0minβ||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
Dies zeigt, dass die ursprüngliche nicht negative Gratregressionsaufgabe gelöst werden kann, indem sie als einfaches eingeschränktes Optimierungsproblem umformuliert wird. Einige Einschränkungen:
- Ich habe (praktisch) normalisierte Prädiktorvariablen verwendet. Sie müssen die Normalisierung selbst berücksichtigen.
- Das Gleiche gilt für die nicht Normalisierung des Abschnitts.
- Früher habe ich
optim
‚s L-BFGS-B - Argument. Es ist der Vanille-R-Löser, der Grenzen akzeptiert. Ich bin sicher, dass Sie Dutzende besserer Löser finden werden.
- Im Allgemeinen werden lineare Probleme mit kleinsten Quadraten als quadratische Optimierungsaufgaben gestellt . Dies ist ein Overkill für diesen Beitrag, aber denken Sie daran, dass Sie bei Bedarf eine bessere Geschwindigkeit erzielen können.
- Wie in den Kommentaren erwähnt, können Sie die Gratregression als Teil der erweiterten linearen Regression überspringen und die Gratkostenfunktion direkt als Optimierungsproblem codieren. Dies wäre viel einfacher und dieser Beitrag deutlich kleiner. Aus Gründen der Argumentation füge ich auch diese zweite Lösung hinzu.
- Ich bin in Python nicht vollständig im Gespräch, aber im Wesentlichen können Sie diese Arbeit mithilfe der Optimierungsfunktionen von NumPy linalg.solve und SciPy replizieren .
- Um den Hyperparameter usw. auszuwählen, führen Sie einfach den üblichen CV-Schritt aus, den Sie auf jeden Fall ausführen würden. Nichts verändert sich.λ
Code für Punkt 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