Modelos lineales generalizados con Python y statsmodels
El modelo lineal generalizado amplía los modelos lineales, de manera que las variables dependientes están relacionadas linealmente con factores y las covariables mediante una determinada función.
Una de las ventajas es que este modelo permite que la variable dependiente tenga una distribución no normal.
Como ejemplo, una empresa de transporte puede utilizar modelos lineales generalizados para ajustar una regresión de Poisson a las frecuencias de rechazo de paso de sus barcos en el canal de Panamá en varios períodos de tiempo. El modelo resultante puede ayudar a determinar cuales son las fechas de mayor rechazo de paso de sus barcos (por atochamiento, reparaciones del canal etc.).
Los modelos lineales generalizados actualmente admiten la estimación utilizando las familias exponenciales de un solo parámetro.
Usando un modelo Gamma
import statsmodels.api as sm data = sm.datasets.scotland.load() data.exog = sm.add_constant(data.exog) gamma_model = sm.GLM(data.endog, data.exog, family=sm.families.Gamma()) gamma_results = gamma_model.fit() print(gamma_results.summary())
Resultados
Generalized Linear Model Regression Results
==============================================================================
Dep. Variable: y No. Observations: 32
Model: GLM Df Residuals: 24
Model Family: Gamma Df Model: 7
Link Function: inverse_power Scale: 0.0035843
Method: IRLS Log-Likelihood: -83.017
Date: Mon, 14 May 2018 Deviance: 0.087389
Time: 21:48:07 Pearson chi2: 0.0860
No. Iterations: 6 Covariance Type: nonrobust
==============================================================================
coef std err z P>|z| [0.025 0.975]
------------------------------------------------------------------------------
const -0.0178 0.011 -1.548 0.122 -0.040 0.005
x1 4.962e-05 1.62e-05 3.060 0.002 1.78e-05 8.14e-05
x2 0.0020 0.001 3.824 0.000 0.001 0.003
x3 -7.181e-05 2.71e-05 -2.648 0.008 -0.000 -1.87e-05
x4 0.0001 4.06e-05 2.757 0.006 3.23e-05 0.000
x5 -1.468e-07 1.24e-07 -1.187 0.235 -3.89e-07 9.56e-08
x6 -0.0005 0.000 -2.159 0.031 -0.001 -4.78e-05
x7 -2.427e-06 7.46e-07 -3.253 0.001 -3.89e-06 -9.65e-07
==============================================================================
Datos binomiales de respuesta
%matplotlib inline from __future__ import print_function import numpy as np import statsmodels.api as sm from scipy import stats from matplotlib import pyplot as plt data = sm.datasets.star98.load() data.exog = sm.add_constant(data.exog, prepend=False) # La variable dependiente es N por 2 (Exito: NABOVE, Fallo: NBELOW): print(data.endog[:5,:])
Resultado
[[452. 355.] [144. 40.] [337. 234.] [395. 178.] [ 8. 57.]]
Ajuste y Resumen
glm_binom = sm.GLM(data.endog, data.exog, family=sm.families.Binomial()) res = glm_binom.fit() print(res.summary())
Resultado
Generalized Linear Model Regression Results
==============================================================================
Dep. Variable: ['y1', 'y2'] No. Observations: 303
Model: GLM Df Residuals: 282
Model Family: Binomial Df Model: 20
Link Function: logit Scale: 1.0000
Method: IRLS Log-Likelihood: -2998.6
Date: Mon, 14 May 2018 Deviance: 4078.8
Time: 21:45:26 Pearson chi2: 4.05e+03
No. Iterations: 5 Covariance Type: nonrobust
==============================================================================
coef std err z P>|z| [0.025 0.975]
------------------------------------------------------------------------------
x1 -0.0168 0.000 -38.749 0.000 -0.018 -0.016
x2 0.0099 0.001 16.505 0.000 0.009 0.011
x3 -0.0187 0.001 -25.182 0.000 -0.020 -0.017
x4 -0.0142 0.000 -32.818 0.000 -0.015 -0.013
x5 0.2545 0.030 8.498 0.000 0.196 0.313
x6 0.2407 0.057 4.212 0.000 0.129 0.353
x7 0.0804 0.014 5.775 0.000 0.053 0.108
x8 -1.9522 0.317 -6.162 0.000 -2.573 -1.331
x9 -0.3341 0.061 -5.453 0.000 -0.454 -0.214
x10 -0.1690 0.033 -5.169 0.000 -0.233 -0.105
x11 0.0049 0.001 3.921 0.000 0.002 0.007
x12 -0.0036 0.000 -15.878 0.000 -0.004 -0.003
x13 -0.0141 0.002 -7.391 0.000 -0.018 -0.010
x14 -0.0040 0.000 -8.450 0.000 -0.005 -0.003
x15 -0.0039 0.001 -4.059 0.000 -0.006 -0.002
x16 0.0917 0.015 6.321 0.000 0.063 0.120
x17 0.0490 0.007 6.574 0.000 0.034 0.064
x18 0.0080 0.001 5.362 0.000 0.005 0.011
x19 0.0002 2.99e-05 7.428 0.000 0.000 0.000
x20 -0.0022 0.000 -6.445 0.000 -0.003 -0.002
const 2.9589 1.547 1.913 0.056 -0.073 5.990
==============================================================================
Valores de Interés
print('Numero de pruebas:', data.endog[0].sum())
print('Parametros: ', res.params)
print('valores-T: ', res.tvalues)
Resultado
numero de pruebas: 807.0 Parametros: [-1.68150366e-02 9.92547661e-03 -1.87242148e-02 -1.42385609e-02 2.54487173e-01 2.40693664e-01 8.04086739e-02 -1.95216050e+00 -3.34086475e-01 -1.69022168e-01 4.91670212e-03 -3.57996435e-03 -1.40765648e-02 -4.00499176e-03 -3.90639579e-03 9.17143006e-02 4.89898381e-02 8.04073890e-03 2.22009503e-04 -2.24924861e-03 2.95887793e+00] valores-T: [-38.74908321 16.50473627 -25.1821894 -32.81791308 8.49827113 4.21247925 5.7749976 -6.16191078 -5.45321673 -5.16865445 3.92119964 -15.87825999 -7.39093058 -8.44963886 -4.05916246 6.3210987 6.57434662 5.36229044 7.42806363 -6.44513698 1.91301155]
Primeras diferencias: mantenemos todas las variables explicativas constantes en sus medios y manipulamos el porcentaje de hogares de bajos ingresos para evaluar su impacto en las variables de respuesta:
means = data.exog.mean(axis=0) means25 = means.copy() means25[0] = stats.scoreatpercentile(data.exog[:,0], 25) means75 = means.copy() means75[0] = lowinc_75per = stats.scoreatpercentile(data.exog[:,0], 75) resp_25 = res.predict(means25) resp_75 = res.predict(means75) diff = resp_75 - resp_25
La primera diferencia intercuartil para el porcentaje de hogares de bajos ingresos en un distrito escolar es:
print("%2.4f%%" % (diff*100))
Resultado
-11.8753%
Written by Tutor