Evaluando el modelo
Clase 14 de 18 • Curso de Regresión Lineal con Python y scikit-learn
Contenido del curso
Clase 14 de 18 • Curso de Regresión Lineal con Python y scikit-learn
Contenido del curso
Alex Junior Rodriguez Huerta
Ever Orlando Reyes Ruiz
Richard Eduardo Sailema Medina
Luis Arces Palomino Blas
Victor Renan Castillo Ñañez
MIGUEL ANGEL ASTAIZA CORDOBA
Cristian Omar Rubio Ceja
Cesar Haziel Pineda Pacheco
Claudio Chavarría Altamirano
Dick Saide Suárez Blanco
Jhon Freddy Tavera Blandon
Rodrigo Martinez
HANSEL BONIFACIO TRUJILLO
jader lopez
Denis Picén
Cristian Enrique Cuevas Mercado
Ronald Andrey Beltran Parada
Dario vallejo
Fernando Jesús Núñez Valdez
Juan R. Vergara M.
Leandro Tenjo
KEVIN XAVIER FREGOSO ROMERO
Luis Fernando Laris Pardo
Javier Castillo
Claudio Fernando Abarca Barrera
Luis Fernando Laris Pardo
Claudio Fernando Abarca Barrera
Gerardo Mayel Fernández Alamilla
Patricio Sánchez Fernández
David Nicolás Montaño Vergara
Olga Lisethe Castellanos Galeano
Brayam Esparza
Antonio Chávez Campos
Antonio Chávez Campos
Eduardo Ramírez
Camilo Vergara
Por si a alguien le sirve como solucioné un error que me tomó buen tiempo:
python -m pip install regressors Collecting regressors Using cached regressors-0.0.3.tar.gz (24 kB) Preparing metadata (setup.py) ... error error: subprocess-exited-with-error × python setup.py egg_info did not run successfully. │ exit code: 1 ╰─> [1 lines of output] error in regressors setup command: use_2to3 is invalid. [end of output] note: This error originates from a subprocess, and is likely not a problem with pip. error: metadata-generation-failed × Encountered error while generating package metadata. ╰─> See above for output. note: This is an issue with the package mentioned above, not pip. hint: See above for details.
Lo solucioné así:
pip install setuptools==58
Yo tenía una versión más actual y eso causaba un conflicto
Me funciono perfecto! Gracias.
Gracias me sirvió totalmente
Para agregar la línea que comenta el maestro es
plt.axhline(y=0, color='r', linestyle='-')
Thanks!
otra manera de hacerlo:
y_values = np.zeros_like(y_pred) plt.plot(y_pred,y_values,"r");
De esta manera sera una linea con los datos reales
Para los que lo están haciendo en Mayo del 2024, tienen 2 soluciones
1. Downgradeas la versión de ty python a las ultimas de python2 o a las primeras de python3, debido con la libreria regressors está depreciada.
2. Utilizas otra librería, en mi caso use statsmodels
%%capture %pip install statsmodels # Add summary of coefficients (estimates, Std. Error, t value, p value) and residuals (min, 1q, median, 3q, max) import statsmodels.api as sm X_train_sm = sm.add_constant(X_train) X_test_sm = sm.add_constant(X_test) model = sm.OLS(y_train, X_train_sm) results = model.fit() print(results.summary())
Este es su output
OLS Regression Results ============================================================================== Dep. Variable: y R-squared: 0.744 Model: OLS Adj. R-squared: 0.742 Method: Least Squares F-statistic: 383.9 Date: Mon, 13 May 2024 Prob (F-statistic): 3.92e-306 Time: 13:03:01 Log-Likelihood: -761.00 No. Observations: 1064 AIC: 1540. Df Residuals: 1055 BIC: 1585. Df Model: 8 Covariance Type: nonrobust ============================================================================== coef std err t P>|t| [0.025 0.975] ------------------------------------------------------------------------------ const -0.0022 0.015 -0.146 0.884 -0.032 0.028 x1 -0.0447 0.019 -2.299 0.022 -0.083 -0.007 x2 0.0655 0.015 4.279 0.000 0.035 0.095 x3 -0.0140 0.019 -0.740 0.460 -0.051 0.023 x4 0.1444 0.016 8.923 0.000 0.113 0.176 x5 0.7862 0.016 50.243 0.000 0.756 0.817 x6 -0.0391 0.019 -2.070 0.039 -0.076 -0.002 x7 0.3064 0.015 19.961 0.000 0.276 0.337 x8 -0.0025 0.015 -0.163 0.870 -0.032 0.027 ============================================================================== Omnibus: 233.259 Durbin-Watson: 1.978 Prob(Omnibus): 0.000 Jarque-Bera (JB): 488.001 Skew: 1.236 Prob(JB): 1.08e-106 Kurtosis: 5.213 Cond. No. 2.22 ============================================================================== ```  
Excelente aporte bb 😘
Buenisimo!
😎----->Evaluando el modelo<----
σ Objetivo es evaluar el modelo hecho en la clase anteior, para ello se usara la libreria llamada regresors.
1 . Se necesita importar las metricas necesarias, para continuar, por ello se usa:
" import sklearn.metrics as metrics " +Estableciendo las abreviaturas que se van a usar en el codigo. " mse = metrics.mean_squared_error(y_test,y_pred)" +" y_test,y_pred "se le va sobre la funcion que se esta evaluando. " r2 = metrics.r2_score(y_test, y_pred) " +El siguiente paso es evaluar "r2" print("r2 ", r2.round(4)) +Ahora se imprimen los valores de r2, mas ponemos una funcion de round 4, osea que de ser numero decimal, se nos muestre hasta el 4to digito. " print("mse: ", mse.round(4))" +Con este ultimo, nos arrojara valores que nos sirven para entender el modelo. ------------> En este ejemplo, Luis recibio los valores de " r2 0.7697 " " mse: 0.2591" A lo que el hace una nota diciendo. que "R2" tiene un 76% mientras que "mse" tiene un 26%. NOTA: Modelo que sea evaluado arriba de 75%, es un aceptable modelo para trabajar, un 85% es excelente y arriba de 95% es casi perfecto. Mas nota que si tiene un modelo de 100%, posiblemente esta solamente evaluando ciertos resultados y no el espectro completo, por ello tal vez este muy ajustado, y ya que corregirlo. 2 . Ahora importart las stadisticas de la librera regressors. usando:
" from regressors import stats " +Debido a que ya debio haber sido instalado regresor anteriormente, uno solo especifica lo que quiere sacar. ----------> Ahora hay que limpiar los pasos del modelo, debido a que la funcion "regressors" necesita que los datos del intercepto y de la pendiente tengan un tipo de formula especifica para que sea mas facil analizar los resultados.
3 . " model.intercept_ = model.intercept_[0] " +Notese que " [0] " se refiere al valor, debido a que
"ahora mismo lo entrega como una lista"
" model.coef_ = model.coef_.reshape(-1) " +Esto permite que cuando apliquemos la funcion que necesitemos utilice los coeficientes y modelos que estan en la libreria "stats" de una forma adecuada. --------->El sig. paso en el codigo es empezar a usar la funcion ya establecida, para ello : 4 . " y_test = y_test.reshape(-1) " + Hacemos un reshape para que se pueda usar de manera correcta. +Y ahora resta imprimir los resultados. para ello hacemos " print("==========Summary==========") " stats.summary(model, X_test, y_test, X_cols) +Summary del modelo, con los datos de prueba, del dato de "x" y "y" NOTAS: Ya que el modelo se entrena con datos que no tiene columnas, entonces se especifia en la tercera coma que las columnas a usar para los datos, son las que estan en las columna X --------->Hasta este punto, debemos de cargar todas las celdas ocupadas en este ejercicio. Y nos mostrara los datos recabados en forma de tabla. 5 . Por ultimo, lo que buscamos es presentar los residuales en graficas, esto usando un scatter.
" residuals = np.subtract(y_test, y_pred.reshape(-1)) " +Con esto se crean los residuales. " plt.scatter(y_pred, residuals) " +Con esto se define la manera en la que se presenta la funcion . +Por un lado se mostrara el scatter de la prediccion de "Y" y por el otro, los residuales. NOTA: Debio a que usamos reshape(-1), en "y_test" ahora lo usamos con "y_pred", y esto es para ambos esten en la misma direccion. No es recomendable usar todas las variables dentro de la regresion lineal. " plt.show() "
residuals = np.subtract(y_test, y_pred.reshape(-1)) plt.scatter(y_pred, residuals) plt.axhline(y=0, color='r', linestyle='--') # Agregar la línea en el valor cero plt.show()
##Error cuadrático medio (MSE, por sus siglas en inglés):
Raíz del error cuadrático medio (RMSE):
Coeficiente de determinación (R^2):
Error absoluto promedio (MAE, por sus siglas en inglés):
Estas métricas pueden ser calculadas utilizando funciones de evaluación de modelos de la biblioteca scikit-learn. Aquí tienes un ejemplo de cómo calcular estas métricas:
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score # Calculando las métricas mse = mean_squared_error(y_test, y_pred) rmse = np.sqrt(mse) mae = mean_absolute_error(y_test, y_pred) r2 = r2_score(y_test, y_pred) # Imprimiendo los resultados print("Error cuadrático medio (MSE):", mse) print("Raíz del error cuadrático medio (RMSE):", rmse) print("Error absoluto promedio (MAE):", mae) print("Coeficiente de determinación (R^2):", r2)
THIS! 🔥
Saludos, he intentado obtener el resumen con regressors .stats, pero aun no he podido, este es el error que obtengo. Esta relacionado a las dimensiones de los Arrays. En pantalla se muestra las dimensiones de cada uno. Agradezco su ayuda. Gracias!!
tenemos el mismo error? ati como te fue, yo sigo analisando el codigo viendo donde surge esta la dimencion que me indica
Yo tuve problema justo en el paso anterior, en el model.intercept_[0]. Por alguna razón a mi me funcionó quitando la parte de los corchetes.
Los residuos vs valores ajustado es ideal para ver si se cumple el supuesto de homogeneidad de varianza en los residuos.
El curso es excelente, pero la librería regressors ya está desactualizada y su instalación falla por conflictos de versiones. Esto obliga a buscar alternativas como statsmodels , lo que cambia el flujo de trabajo del profesor.
Sería de gran ayuda que se actualizara el contenido o se agregara una nota con las alternativas actuales para mantener la clase vigente.
Mil gracias los amo.
Hay una solucion incluso más sencilla, aqui te explico y te pongo el codigo:
import statsmodels.api as sm
import pandas as pd
# Añadir una constante a las características (X) para el término de intercepción
X_sm_test = sm.add_constant(pd.DataFrame(x_test, columns=x_columns))
# Crear y ajustar el modelo OLS (Ordinary Least Squares)
# Nota: statsmodels espera y, X (dependiente, independiente) al revés que scikit-learn
sm_model = sm.OLS(y_test, X_sm_test)
results = sm_model.fit()
# Imprimir el resumen del modelo
print(results.summary())Podemos usar el modulo de plots de la paquetería regressors que instalamos de la siguiente manera para obtener un grafico como el siguiente:
from regressors import plots # Restaurar las variables X_train y y_train para no tener problemas de dimensionalidad. # El model es al que le hicimos el fit con los datos del train. plots.plot_residuals(model, X_train, y_train, r_type='standardized')
Es más detallado, gracias.
📈 Mejorar graficó de ++Residuales++
plt.axvline(x = 0, c='k', ls='--', alpha=0.5) plt.axhline(y = 0, c='k', ls='--', alpha=0.5) plt.scatter(y_pred, residuals, alpha=0.25) plt.xlabel('Predicciones') plt.ylabel('Realidad') plt.title('Residueles: Diferencia entre prediccion y realidad') plt.show()
EStoy tratando de instalar regressors ya reinicie el kernel de mi ambiente en visual y trate en google colab pero me marca esto ERROR: Could not find a version that satisfies the requirement regresors (from versions: none) ERROR: No matching distribution found for regresors
Ese error es porque no encontró la distribución, me parece por lo que muestras que te faltó una s en regressors, avísame si esto te lo soluciona 😄
pip install --upgrade pip setuptools==57.5.0
¿Entre que rango debiera estar el MSE para ser considerado un buen modelo?
Es complicado porque el MSE es proporcional a la magnitud de tu variable predictora. Es decir si hablamos de millones, entonces obtenemos un MSE de 100, que puede parecer grande, pero 100 es bajo cuando hablamos de millones, a comparación de si tenemos una variable predictora que están en las décimas donde un MSE de 100. Esto debido a que el MSE su utiliza una función de distancia. ¿Tiene sentido?
Claro, a eso mismo apunta mi pregunta. Entiendo el porqué usar el MSE como función de pérdida para optimizar el modelo, pero no veo claro su uso como métrica para evaluar el mismo. Al usar R2 por ejemplo, su interpretación y rangos son bastante intuitivos, no así con el MSE. En ese caso, creo que sería preferible usar el RMSE, que al menos se puede interpretar de mejor manera al tener las mismas "unidades de medida" que la variable.
si tuvieron error con regressors existe otro método que se puede utilizar para obtener el summary:
import statsmodels.api as sm
# Transforma de nuevo los datos de entrenamiento a su escala original
X_train_original = sc_x.inverse_transform(X_train)
y_train_original = sc_y.inverse_transform(y_train)
# Añadir una constante (intercepto) a los predictores
X_train_const = sm.add_constant(X_train_original)
# Ajustar el modelo OLS
ols_model = sm.OLS(y_train_original, X_train_const).fit()
# Imprimir un resumen del modelo
print(ols_model.summary())
Se obtiene:
OLS Regression Results
==============================================================================
Dep. Variable: y R-squared: 0.998
Model: OLS Adj. R-squared: 0.998
Method: Least Squares F-statistic: 5.588e+04
Date: Tue, 31 Oct 2023 Prob (F-statistic): 0.00
Time: 23:28:51 Log-Likelihood: -7709.6
No. Observations: 1003 AIC: 1.544e+04
Df Residuals: 993 BIC: 1.549e+04
Df Model: 9
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const -46.1883 104.998 -0.440 0.660 -252.231 159.855
x1 -9.2017 48.414 -0.190 0.849 -104.207 85.803
x2 -2.7928 1.381 -2.022 0.043 -5.503 -0.083
x3 44.3569 47.450 0.935 0.350 -48.757 137.471
x4 -1.7757 13.922 -0.128 0.899 -29.096 25.545
x5 -19.5770 33.683 -0.581 0.561 -85.675 46.521
x6 -137.3153 77.197 -1.779 0.076 -288.804 14.173
x7 1.8920 3.036 0.623 0.533 -4.066 7.850
x8 1.0134 0.003 358.908 0.000 1.008 1.019
x9 -54.5896 47.967 -1.138 0.255 -148.717 39.538
==============================================================================
Omnibus: 2112.965 Durbin-Watson: 2.010
Prob(Omnibus): 0.000 Jarque-Bera (JB): 4346097.201
Skew: 17.118 Prob(JB): 0.00
Kurtosis: 323.659 Cond. No. 1.17e+05
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 1.17e+05. This might indicate that there are
strong multicollinearity or other numerical problems.
El código que escribió el profe me arrojó error, así que "San-ChatGPT" Me indicó la siguiente solución:
import sklearn.metrics as metrics mse = metrics.mean_squared_error(y_test, Y_pred) r2 = metrics.r2_score(y_test, Y_pred) print('mse:', round(mse, 4)) print('r2:', round(r2, 4))
Para todos los que tengan problemas en la linea de stats.summary aqui una solucion que encontre:
from regressors import stats model.intercept_ = model.intercept_model.coef_ = model.coef_.reshape(-1)y_test = y_test.reshape(-1)y_pred = y_pred.reshape(-1)print("--------------Summary---------------------")stats.summary(model, x_test, y_test, x_cols)
Corran esta linea en un solo cuadro. De igual manera, noten que se estan cambiando las dimensiones de y_test y y_predict y los coeficientes no son exactamente iguales a las del video
excelente sugerencia, me funcionó
entre mas cerca del cero esten valores en la grafica es mejor?
ValueError: all the input arrays must have same number of dimensions, but the array at index 0 has 1 dimension(s) and the array at index 1 has 2 dimension(s)
Tengo este error IndexError: invalid index to scalar variable.
acá ---> model.intercept_ = model.intercept_[0]
Por si tienen error con regressors, pueden usar esto para solucionarlo:
!pip install --upgrade pip setuptools==57.5.0
!pip install regressors
Yo, como varios en esta clase, no pude instalar la librería que el profesor utiliza. Trate de varias formas y no pude, por lo que fui a esta [página](https://regressors.readthedocs.io/en/latest/\_modules/regressors/stats.html#summary) en la cual está la documentación. Con base en esta documentación replique el código con unos ligeros cambios:
import numpy as npimport pandas as pdimport scipyfrom sklearn.metrics import mean_squared_error, r2_scoreclass stats_model: def __init__(self, model, X, y, x_labels=None) -> None: """ model es el modelo lineal de scikit-learn que tiene un método predict() X es la data de entrenamiento y es las etiquetas de entrenamiento xlabels son el nombre de las variables predictores X e y deben estar previamente estandarizados (usar StandardScaler de sklearn) """ self.model = model self.X = X self.y = y self.x_labels = x_labels def metrics(self,y_real, y_pred,metric): assert metric in ["mse","r2","adj_r2"],"Not a valid metric" if metric=="mse": return mean_squared_error(y_real, y_pred) elif metric == "adj_r2": n,p=X.shape r_2 = r2_score(y_real,y_pred) return 1 - (1 - r_2) * ((n-1)/(n-p-1)) return r2_score(y_real,y_pred) def coef_se(self): """ calculate standard error """ n = self.X.shape[0] #We create a matrix nx1 full of ones and we concatenate it to #the X data X1 = np.hstack((np.ones((n,1)),self.X)) #The standard error of every coefficient of the regression is calculated se_matrix = scipy.linalg.sqrtm(self.metrics(self.y, self.model.predict(self.X), "mse")* np.linalg.inv(np.matmul(X1.T,X1))) #We get a list of standard errors of the regression's coeffiecients, which #indicates how much it varies depending on the variability of the input data return np.diagonal(se_matrix) def coef_tval(self): coef_standard_error = self.coef_se() a = np.array(self.model.intercept_/coef_standard_error[0]) b = np.array(self.model.coef_/coef_standard_error[1:]) return np.append(a,b) def coef_pval(self): n = self.X.shape[0] t = self.coef_tval() #este valor p lo usaremos para saber si necesitamos o no usar una variable, #ya que representa si p = 2 * (1 - scipy.stats.t.cdf(abs(t),n-1)) return p def residuals(self): y_pred = self.model.predict(self.X) return np.subtract(self.y,y_pred).reshape(-1) def f_stat(self): n,p = self.X.shape y_pred = self.model.predict(self.X) r_2 = self.metrics(self.y,y_pred,metric="r2") return (r_2/p) / ((1-r2)/(n-p-1)) def summary(self): # Check and/or make xlabels ncols = self.X.shape[1] xlabels = self.x_labels if xlabels is None: #If labels do not exist, they'll be created as x1, x2,x3... xlabels = np.array( [f'x{i}' for i in range(1, ncols + 1)], dtype='str') elif isinstance(xlabels, (tuple, list)): #if xlabels is either a list or a tuple, we'll use that #to create a numpy array xlabels = np.array(xlabels, dtype='str') # Make sure dims of xlabels matches dims of X assert xlabels.shape[0] == ncols, f"Dimension of xlabels {xlabels.shape} does not match X {X.shape}" # Create data frame of coefficient estimates and associated stats coef_df = pd.DataFrame( index=['_intercept'] + list(xlabels), columns=['Estimate', 'Std. Error', 't value', 'p value'] ) coef_df['Estimate'] = np.concatenate( (np.round(np.array([self.model.intercept_]), 6).reshape(-1,1), np.round((self.model.coef_), 6).reshape(-1,1))) coef_df['Std. Error'] = np.round(self.coef_se(), 6) coef_df['t value'] = np.round(self.coef_tval(), 4) coef_df['p value'] = np.round(self.coef_pval(), 6) # Create data frame to summarize residuals resids = self.residuals() resids_df = pd.DataFrame({ 'Min': pd.Series(np.round(resids.min(), 4)), '1Q': pd.Series(np.round(np.percentile(resids, q=25), 4)), 'Median': pd.Series(np.round(np.median(resids), 4)), '3Q': pd.Series(np.round(np.percentile(resids, q=75), 4)), 'Max': pd.Series(np.round(resids.max(), 4)), }, columns=['Min', '1Q', 'Median', '3Q', 'Max']) # Output results print("Residuals:") print(resids_df.to_string(index=False)) print('\n') print('Coefficients:') print(coef_df.to_string(index=True)) print('---') print('R-squared: {0:.5f}, Adjusted R-squared: {1:.5f}'.format( self.metrics(self.y, self.model.predict(self.X),"r2"), self.metrics(self.y,self.model.predict(self.X),"adj_r2"))) print('F-statistic: {0:.2f} on {1} features'.format( self.f_stat(), ncols))