scikit-learn & statsmodels – ¿cuál R-cuadrado es correcto?

Me gustaría elegir el mejor algoritmo para el futuro. Encontré algunas soluciones, pero no entendí qué valor de R-Squared es correcto.

Para esto, dividí mis datos en dos como prueba y entrenamiento, e imprimí dos valores de R al cuadrado diferentes a continuación.

import statsmodels.api as sm from sklearn.linear_model import LinearRegression from sklearn.metrics import r2_score lineer = LinearRegression() lineer.fit(x_train,y_train) lineerPredict = lineer.predict(x_test) scoreLineer = r2_score(y_test, lineerPredict) # First R-Squared model = sm.OLS(lineerPredict, y_test) print(model.fit().summary()) # Second R-Squared 

El primer resultado R-Squared es -4.28.
El segundo resultado R-Squared es 0.84

Pero no entendí qué valor es correcto.

Podría decirse que el verdadero desafío en tales casos es asegurarse de comparar manzanas con manzanas. Y en tu caso, parece que no lo haces. Nuestro mejor amigo es siempre la documentación relevante, combinada con experiencias simples. Asi que…

Si bien LinearRegression() scikit-learn (es decir, su primer R-cuadrado) se ajusta de forma predeterminada con fit_intercept=True ( docs ), este no es el caso con el OLS statsmodels (su segundo R-squared); citando de los documentos :

Una intercepción no se incluye de forma predeterminada y debe ser agregada por el usuario. Ver statsmodels.tools.add_constant .

Teniendo en cuenta este importante detalle, hagamos algunos experimentos simples con datos ficticios:

 import numpy as np import statsmodels.api as sm from sklearn.metrics import r2_score from sklearn.linear_model import LinearRegression # dummy data: y = np.array([1,3,4,5,2,3,4]) X = np.array(range(1,8)).reshape(-1,1) # reshape to column # scikit-learn: lr = LinearRegression() lr.fit(X,y) # LinearRegression(copy_X=True, fit_intercept=True, n_jobs=None, # normalize=False) lr.score(X,y) # 0.16118421052631582 y_pred=lr.predict(X) r2_score(y, y_pred) # 0.16118421052631582 # statsmodels # first artificially add intercept to X, as advised in the docs: X_ = sm.add_constant(X) model = sm.OLS(y,X_) # X_ here results = model.fit() results.rsquared # 0.16118421052631593 

Para todos los propósitos prácticos, estos dos valores de R-cuadrado producidos por scikit-learn y statsmodels son idénticos .

Vayamos un paso más allá, y probemos un modelo de aprendizaje de scikit sin intercepción, pero donde usamos los datos “interceptados” artificialmente que ya hemos creado para usar con statsmodels:

 lr2 = LinearRegression(fit_intercept=False) lr2.fit(X_,y) # X_ here # LinearRegression(copy_X=True, fit_intercept=False, n_jobs=None, # normalize=False) lr2.score(X_, y) # 0.16118421052631593 y_pred2 = lr2.predict(X_) r2_score(y, y_pred2) # 0.16118421052631593 

Nuevamente, el R-cuadrado es idéntico a los valores anteriores.

Entonces, ¿qué sucede cuando “accidentalmente” olvidamos tener en cuenta el hecho de que statsmodels OLS está equipado sin una intercepción? Veamos:

 model3 = sm.OLS(y,X) # X here, ie no intercept results3 = model2.fit() results3.rsquared # 0.8058035714285714 

Bueno, un R cuadrado de 0.80 está muy lejos del 0.16 devuelto por un modelo con una intercepción, y podría decirse que esto es exactamente lo que sucedió en su caso.

Hasta aquí todo bien, y fácilmente podría terminar la respuesta aquí; pero de hecho, hay un punto en el que este mundo armonioso se rompe: veamos qué sucede cuando ajustamos ambos modelos sin intercepción y con los datos iniciales X donde no hemos agregado ninguna intercepción artificialmente. Ya hemos instalado el modelo OLS arriba, y obtuvimos una R cuadrada de 0.80; ¿Qué pasa con un modelo similar de scikit-learn?

 # scikit-learn lr3 = LinearRegression(fit_intercept=False) lr3.fit(X,y) # X here lr3.score(X,y) # -0.4309210526315792 y_pred3 = lr3.predict(X) r2_score(y, y_pred3) # -0.4309210526315792 

Ups …! ¿Qué diablos?

Parece que scikit-earn, cuando calcula r2_score , siempre asume una intercepción, ya sea explícitamente en el modelo ( fit_intercept=True ) o implícitamente en los datos (la forma en que hemos producido X_ partir de X , usando add_constant de add_constant ); cavar un poco en línea revela un hilo Github (cerrado sin remedio) donde se confirma que la situación es así.

Permítame aclarar que la discrepancia que he descrito anteriormente no tiene nada que ver con su problema: en su caso, el problema real es que en realidad está comparando manzanas (un modelo con intercepción) con naranjas (un modelo sin intercepción).


Entonces, ¿por qué scikit-learn no solo falla en este caso (es cierto que es una ventaja ), sino que incluso cuando el hecho surge en un problema de Github, en realidad se trata con indiferencia ? (Tenga en cuenta también que el desarrollador central de scikit-learn que responde en el hilo anterior admite de manera casual que ” no estoy muy familiarizado con las estadísticas ” …).

La respuesta va un poco más allá de los problemas de encoding, como aquellos sobre los que se trata principalmente, pero puede valer la pena explicarlo un poco aquí.

Podría decirse que la razón es que todo el concepto de R cuadrado viene de hecho directamente del mundo de las estadísticas, donde el énfasis está en los modelos interpretativos , y tiene poco uso en contextos de aprendizaje automático, donde el énfasis está claramente en los modelos predictivos ; al menos AFAIK, y más allá de algunos cursos muy introductorios, nunca (me refiero a nunca …) he visto un problema de modelado predictivo en el que se utiliza el R cuadrado para cualquier tipo de evaluación de desempeño; tampoco es un accidente que las introducciones populares del aprendizaje automático , como el Aprendizaje automático de Andrew Ng en Coursera, ni siquiera se molesten en mencionarlo. Y, como se señaló en el hilo de Github anterior (énfasis agregado):

En particular, cuando se usa un conjunto de prueba , no está claro qué significa la R ^ 2.

Con lo que ciertamente estoy de acuerdo.

En cuanto al caso de borde discutido anteriormente (¿incluir o no un término de intercepción?), Sospecho que sonaría realmente irrelevante para los practicantes modernos de aprendizaje profundo, donde el equivalente de una intercepción (parámetros de sesgo) siempre se incluye por defecto en los modelos de redes neuronales …

Vea la respuesta aceptada (y altamente upvoted) en la pregunta de validación cruzada Diferencia entre statsmodel OLS y regresión lineal de scikit para una discusión más detallada en estas últimas líneas …

Parece que estás usando sklearn.metrics_r2_score . La documentación indica que “la mejor puntuación posible es 1.0 y puede ser negativa (porque el modelo puede ser arbitrariamente peor)”

El artículo de Wikipedia que lleva a la documentación señala que “los valores de R2 fuera del rango 0 a 1 pueden ocurrir cuando el modelo se ajusta a los datos peor que a un plano de plano horizontal. Esto ocurriría cuando se eligiera el modelo incorrecto o se aplicaran restricciones sin sentido por error”. Por esta razón, el hecho de que tuvieras una puntuación r2 tan negativa es probablemente mucho más significativo que el que tuviste una estadística R ^ 2 relativamente buena (pero no excelente) calculada de la otra manera. Si la primera puntuación indica que su elección de modelo es deficiente, es probable que la segunda estadística sea solo un artefacto de sobrealimentación.

En última instancia, esto es más una cuestión de metodología que una pregunta de progtwigción. Es posible que desee publicar una pregunta de seguimiento en Validada cruzada sobre cómo interpretar un modelo en el que las dos versiones de R ^ 2 difieren enormemente. Si publica una pregunta de este tipo, asegúrese de proporcionar un poco más de información sobre lo que está modelando.

Como usted nota, y como lo señala el artículo de Wikipedia , hay múltiples definiciones de “r al cuadrado” o “R al cuadrado”. Sin embargo, todos los comunes tienen la propiedad de que van de 0 a 1 . Por lo general, son positivos, como se desprende de la parte “cuadrada” del nombre. (Para las excepciones a esta regla general, vea el artículo de Wikipedia).

Su “Primer resultado R-Squared” es -4.28 , que no está entre 0 y 1 y ni siquiera es positivo. Por lo tanto, no es realmente una “R al cuadrado” en absoluto. Entonces use el “Segundo resultado R-Squared” que está en el rango correcto.

No dices qué biblioteca estás usando, por lo que no puedo decir cuál es tu “Primer resultado de R-Squared” en realidad. A partir de ahora, cuando haga una pregunta aquí, muestre un fragmento de código completo que podamos copiar y pegar y ejecutar. Recuerde incluir todas las declaraciones de import .