Logistische Regression: Scikit Learn vs glmnet

15

Ich versuche, die Ergebnisse aus der sklearnlogistischen Regressionsbibliothek mit glmnetpackage in R zu duplizieren .

Aus der Dokumentation der sklearnlogistischen Regression geht es darum, die Kostenfunktion unter l2 Penalty

minw,c12wTw+Ci=1Nlog(exp(yi(XiTw+c))+1)

Ausgehend von den Vignetten von glmnetminimiert seine Implementierung eine geringfügig andere Kostenfunktion

minβ,β0[1Ni=1Nyi(β0+xiTβ)log(1+e(β0+xiTβ))]+λ[(α1)||β||22/2+α||β||1]

Mit ein paar Änderungen in der zweiten Gleichung und durch Setzen von α=0 wird

λminβ,β01Nλi=1N[yi(β0+xiTβ)+log(1+e(β0+xiTβ))]+||β||22/2

was sich von der sklearnKostenfunktion nur um einen Faktor von λ wenn 1Nλ=C , also habe ich die gleiche Koeffizientenschätzung von den beiden Paketen erwartet. Aber sie sind unterschiedlich. Ich verwende den Datensatz von der UCLA idre Tutorial , die Vorhersage admitbasiert auf gre, gpaund rank. Es gibt 400 Beobachtungen, also mit C=1 , λ=0,0025 .

#python sklearn
df = pd.read_csv("https://stats.idre.ucla.edu/stat/data/binary.csv")
y, X = dmatrices('admit ~ gre + gpa + C(rank)', df, return_type = 'dataframe')
X.head()
>  Intercept  C(rank)[T.2]  C(rank)[T.3]  C(rank)[T.4]  gre   gpa
0          1             0             1             0  380  3.61
1          1             0             1             0  660  3.67
2          1             0             0             0  800  4.00
3          1             0             0             1  640  3.19
4          1             0             0             1  520  2.93

model = LogisticRegression(fit_intercept = False, C = 1)
mdl = model.fit(X, y)
model.coef_
> array([[-1.35417783, -0.71628751, -1.26038726, -1.49762706,  0.00169198,
     0.13992661]]) 
# corresponding to predictors [Intercept, rank_2, rank_3, rank_4, gre, gpa]


> # R glmnet
> df = fread("https://stats.idre.ucla.edu/stat/data/binary.csv")
> X = as.matrix(model.matrix(admit~gre+gpa+as.factor(rank), data=df))[,2:6]
> y = df[, admit]
> mylogit <- glmnet(X, y, family = "binomial", alpha = 0)
> coef(mylogit, s = 0.0025)
6 x 1 sparse Matrix of class "dgCMatrix"
                    1
(Intercept)      -3.984226893
gre               0.002216795
gpa               0.772048342
as.factor(rank)2 -0.530731081
as.factor(rank)3 -1.164306231
as.factor(rank)4 -1.354160642

Die RAusgabe kommt der logistischen Regression ohne Regularisierung in gewisser Weise nahe, wie hier zu sehen ist . Vermisse ich etwas oder mache ich offensichtlich etwas falsch?

Update: Ich habe auch versucht, LiblineaRpackage in Rzu verwenden, um denselben Prozess durchzuführen, und habe noch einen anderen Satz von Schätzungen erhalten ( liblinearist auch der Löser in sklearn):

> fit = LiblineaR(X, y, type = 0, cost = 1)
> print(fit)
$TypeDetail
[1] "L2-regularized logistic regression primal (L2R_LR)"
$Type
[1] 0
$W
            gre          gpa as.factor(rank)2 as.factor(rank)3 as.factor(rank)4         Bias
[1,] 0.00113215 7.321421e-06     5.354841e-07     1.353818e-06      9.59564e-07 2.395513e-06

Update 2: Deaktivieren der Standardisierung in glmnetgibt:

> mylogit <- glmnet(X, y, family = "binomial", alpha = 0, standardize = F)
> coef(mylogit, s = 0.0025)
6 x 1 sparse Matrix of class "dgCMatrix"
                     1
(Intercept)      -2.8180677693
gre               0.0034434192
gpa               0.0001882333
as.factor(rank)2  0.0001268816
as.factor(rank)3 -0.0002259491
as.factor(rank)4 -0.0002028832
hurrikale
quelle
Hast du das jemals herausgefunden?
Huey

Antworten:

8

L2

Insbesondere, da Ihr greBegriff so umfangreich ist wie die anderen Variablen, ändern sich dadurch die relativen Kosten für die Verwendung der verschiedenen Variablen für die Gewichtung.

Beachten Sie auch, dass Sie durch Einfügen eines expliziten Intercept-Terms in die Features den Intercept des Modells regulieren. Dies wird im Allgemeinen nicht durchgeführt, da dies bedeutet, dass Ihr Modell nicht länger kovariant dafür ist, alle Beschriftungen um eine Konstante zu verschieben.

Dougal
quelle
glmnetErmöglicht das Ausschalten der Standardisierung der Eingänge, aber die geschätzten Koeffizienten sind noch unterschiedlicher, siehe oben. Auch ich explizit eingeschlossen Intercept Begriff in sklearnda glmnetschließt man automatisch, so dass diese sicher zu machen ist , dass die Eingabe in beiden Modellen gleich ist.
Hurrikale
2
@hurrikale Ich denke, glmnet reguliert wahrscheinlich nicht das Abfangen, aber sklearn ist es. Löschen Sie die Abfangspalte von Xund übergeben Sie sie fit_intercept=True(Standardeinstellung) an LogisticRegression. Wahrscheinlich ist aber noch etwas anderes los.
Dougal
Ich habe versucht, was Sie vorgeschlagen haben, und habe dennoch verschiedene Koeffizientensätze erhalten: [-1.873, -0.0606, -1.175, -1.378, 0.00182, 0.2435]für sklearnund [-2.8181, 0.0001269, -0.0002259, -0.00020288, 0.00344, 0.000188]für glmnetin der Reihenfolge von [Intercept, rank_2, rank_3, rank_4, gre, gpa]. Mein Anliegen ist, dass sie sich sowohl in der Größe als auch in der positiven / negativen Auswirkung auf die Wahrscheinlichkeit unterscheiden. Ohne zu wissen, warum sie sich unterscheiden, ist es schwierig, eine zu wählen, die interpretiert werden soll. Und wenn es zufällig einen Fehler in einer der Implementierungen gibt, ist es besonders wichtig, dass ich weiß, auf welche ich mich verlassen kann.
Hurrikale
7

Dougals Antwort ist richtig. Sie regulieren den Achsenabschnitt in, sklearnaber nicht in R. Stellen Sie sicher, dass Sie sie verwenden, solver='newton-cg'da default solver ( 'liblinear') den Achsenabschnitt immer reguliert.

Siehe https://github.com/scikit-learn/scikit-learn/issues/6595

TomDLT
quelle
Einstellung solver='newton-cg'machte die Ergebnisse aus sklearnund statsmodelskonsistent. Danke vielmals.
Irene
0

Sie sollten auch das L1_wt=0Argument zusammen mit alphain fit_regularized()call verwenden.

Dieser Code in statsmodels:

import statsmodels.api as sm
res = sm.GLM(y, X, family=sm.families.Binomial()).fit_regularized(alpha=1/(y.shape[0]*C), L1_wt=0)

entspricht dem folgenden Code von sklearn:

from sklearn import linear_model
clf = linear_model.LogisticRegression(C = C)
clf.fit(X, y)

Ich hoffe es hilft!

Praful Gupta
quelle