3. Modelo de regresión lineal múltiple
Python
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
from sklearn.preprocessing import StandardScaler, MaxAbsScalerPython
# Seleccionar las variables de interés
variables = [
"PERIODO",
"PUNT_MATEMATICAS",
"ESTU_GENERO",
"FAMI_TIENECOMPUTADOR",
"FAMI_TIENEINTERNET",
"FAMI_ESTRATOVIVIENDA",
"COLE_COD_DANE_SEDE",
"COLE_COD_MCPIO_UBICACION",
"COLE_NATURALEZA",
'FAMI_EDUCACIONPADRE',
'FAMI_EDUCACIONMADRE',
'COLE_JORNADA',
'COLE_BILINGUE',
'COLE_CARACTER',
'FAMI_PERSONASHOGAR',
'FAMI_CUARTOSHOGAR',
'ESTU_DEDICACIONLECTURADIARIA',
'ESTU_DEDICACIONINTERNET',
'FAMI_TRABAJOLABORPADRE',
'FAMI_TRABAJOLABORMADRE',
'FAMI_TIENELAVADORA',
'FAMI_TIENEHORNOMICROOGAS',
'FAMI_TIENEAUTOMOVIL',
'FAMI_TIENEMOTOCICLETA',
'FAMI_TIENECONSOLAVIDEOJUEGOS',
'FAMI_COMELECHEDERIVADOS',
'FAMI_COMECARNEPESCADOHUEVO',
'FAMI_COMECEREALFRUTOSLEGUMBRE',
'ESTU_HORASSEMANATRABAJA',
"COLE_JORNADA"
]Python
# Normalizamos y usamos solo las variables objetivos que tenemos como interes.
saber11_n = saber11[variables]
saber11_n| PERIODO | PUNT_MATEMATICAS | ESTU_GENERO | FAMI_TIENECOMPUTADOR | FAMI_TIENEINTERNET | FAMI_ESTRATOVIVIENDA | COLE_COD_DANE_SEDE | COLE_COD_MCPIO_UBICACION | COLE_NATURALEZA | FAMI_EDUCACIONPADRE | ... | FAMI_TIENELAVADORA | FAMI_TIENEHORNOMICROOGAS | FAMI_TIENEAUTOMOVIL | FAMI_TIENEMOTOCICLETA | FAMI_TIENECONSOLAVIDEOJUEGOS | FAMI_COMELECHEDERIVADOS | FAMI_COMECARNEPESCADOHUEVO | FAMI_COMECEREALFRUTOSLEGUMBRE | ESTU_HORASSEMANATRABAJA | COLE_JORNADA | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 20181 | 46 | F | Si | Si | Estrato 3 | 319001002330 | 19001 | NO OFICIAL | Secundaria (Bachillerato) completa | ... | Si | Si | No | No | No | Todos o casi todos los días | Todos o casi todos los días | 3 a 5 veces por semana | 0 | MAÑANA |
| 1 | 20181 | 62 | M | Si | Si | Estrato 4 | 319001002330 | 19001 | NO OFICIAL | Educación profesional completa | ... | Si | Si | Si | Si | Si | Todos o casi todos los días | Todos o casi todos los días | 1 o 2 veces por semana | 0 | MAÑANA |
| 2 | 20181 | 43 | F | No | No | Estrato 1 | 319001002330 | 19001 | NO OFICIAL | Secundaria (Bachillerato) completa | ... | No | No | No | No | No | Todos o casi todos los días | Nunca o rara vez comemos eso | Todos o casi todos los días | 0 | MAÑANA |
| 3 | 20181 | 75 | M | Si | No | Estrato 1 | 319001002330 | 19001 | NO OFICIAL | Primaria completa | ... | No | Si | Si | No | Si | Todos o casi todos los días | Todos o casi todos los días | Nunca o rara vez comemos eso | 0 | MAÑANA |
| 4 | 20181 | 62 | F | Si | Si | Estrato 2 | 319001002330 | 19001 | NO OFICIAL | Técnica o tecnológica completa | ... | No | No | No | No | No | Todos o casi todos los días | 3 a 5 veces por semana | 1 o 2 veces por semana | 0 | MAÑANA |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2775277 | 20234 | 38 | F | No | Si | Estrato 2 | 117444000818 | 17444 | OFICIAL | Primaria completa | ... | No | No | No | No | No | 1 o 2 veces por semana | Todos o casi todos los días | 1 o 2 veces por semana | 0 | UNICA |
| 2775278 | 20234 | 48 | F | No | Si | Estrato 1 | 117444000818 | 17444 | OFICIAL | Secundaria (Bachillerato) completa | ... | Si | No | No | Si | No | 3 a 5 veces por semana | Nunca o rara vez comemos eso | Todos o casi todos los días | 0 | UNICA |
| 2775279 | 20234 | 61 | F | No | No | Estrato 1 | 173283000038 | 73283 | OFICIAL | Primaria completa | ... | Si | No | No | No | No | 1 o 2 veces por semana | 3 a 5 veces por semana | Nunca o rara vez comemos eso | 0 | UNICA |
| 2775280 | 20234 | 73 | F | Si | Si | Estrato 3 | 173283000038 | 73283 | OFICIAL | Educación profesional completa | ... | Si | Si | Si | No | No | 3 a 5 veces por semana | Todos o casi todos los días | 3 a 5 veces por semana | 0 | UNICA |
| 2775281 | 20234 | 43 | F | No | No | Estrato 1 | 223807002839 | 23807 | OFICIAL | Secundaria (Bachillerato) completa | ... | Si | No | No | Si | No | 1 o 2 veces por semana | 1 o 2 veces por semana | 3 a 5 veces por semana | 0 | UNICA |
2775282 rows × 30 columns
Python
saber11_n['PERIODO'].unique()salida
array([20181, 20182, 20191, 20194, 20201, 20204, 20211, 20214, 20221,
20231, 20234])Python
# Filtrar los datos por colegios públicos de Bogotá
saber11_n = saber11_n[(saber11_n['COLE_COD_MCPIO_UBICACION'] == 11001)]Python
saber11_n['PERIODO'].unique()salida
array([20181, 20182, 20191, 20194, 20201, 20204, 20211, 20214, 20221,
20231, 20234])Python
# Convertir variables categóricas a variables dummy
saber11_n = pd.get_dummies(
data=saber11_n,
prefix="OHE",
prefix_sep="_",
columns=[
"ESTU_GENERO",
"FAMI_ESTRATOVIVIENDA",
"COLE_NATURALEZA",
'FAMI_EDUCACIONPADRE',
'FAMI_EDUCACIONMADRE',
'COLE_JORNADA',
'COLE_BILINGUE',
'COLE_CARACTER',
'FAMI_PERSONASHOGAR',
'FAMI_CUARTOSHOGAR',
'ESTU_DEDICACIONLECTURADIARIA',
'ESTU_DEDICACIONINTERNET',
'FAMI_TRABAJOLABORPADRE',
'FAMI_TRABAJOLABORMADRE',
'FAMI_TIENELAVADORA',
'FAMI_TIENEHORNOMICROOGAS',
'FAMI_TIENEAUTOMOVIL',
'FAMI_TIENEMOTOCICLETA',
'FAMI_TIENECONSOLAVIDEOJUEGOS',
'FAMI_COMELECHEDERIVADOS',
'FAMI_COMECARNEPESCADOHUEVO',
'FAMI_COMECEREALFRUTOSLEGUMBRE',
'ESTU_HORASSEMANATRABAJA',
],
drop_first=True,
dtype="int8",
)
saber11*n = pd.get_dummies(
data=saber11_n,
prefix=["FAMI_TIENECOMPUTADOR", "FAMI_TIENEINTERNET"], # Especificar prefijos diferentes para cada variable
prefix_sep="*",
columns=["FAMI_TIENECOMPUTADOR", "FAMI_TIENEINTERNET"], # Especificar las columnas a codificar
drop_first=True,
dtype="int8",
)
saber11_n| PERIODO | PUNT_MATEMATICAS | COLE_COD_DANE_SEDE | COLE_COD_MCPIO_UBICACION | OHE_M | OHE_Estrato 2 | OHE_Estrato 3 | OHE_Estrato 4 | OHE_Estrato 5 | OHE_Estrato 6 | ... | OHE_Todos o casi todos los días | OHE_3 a 5 veces por semana | OHE_Nunca o rara vez comemos eso | OHE_Todos o casi todos los días | OHE_Entre 11 y 20 horas | OHE_Entre 21 y 30 horas | OHE_Menos de 10 horas | OHE_Más de 30 horas | FAMI_TIENECOMPUTADOR_Si | FAMI_TIENEINTERNET_Si | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 266 | 20181 | 74 | 311001042667 | 11001 | 1 | 0 | 0 | 0 | 0 | 1 | ... | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 |
| 267 | 20181 | 78 | 311001042667 | 11001 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 268 | 20181 | 78 | 311001042667 | 11001 | 0 | 0 | 0 | 0 | 1 | 0 | ... | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
| 269 | 20181 | 60 | 311001042667 | 11001 | 0 | 0 | 0 | 1 | 0 | 0 | ... | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 |
| 270 | 20181 | 63 | 311001042667 | 11001 | 0 | 0 | 0 | 0 | 0 | 1 | ... | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2775242 | 20234 | 44 | 311001005451 | 11001 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
| 2775259 | 20234 | 25 | 111001044385 | 11001 | 1 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2775260 | 20234 | 41 | 111001010928 | 11001 | 1 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2775264 | 20234 | 26 | 111001044385 | 11001 | 1 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2775267 | 20234 | 33 | 111001044385 | 11001 | 1 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
423240 rows × 109 columns
Revisamos las nuevas columnas añadidas recientemente.
Python
saber11_n.columnssalida
Index(['PERIODO', 'PUNT_MATEMATICAS', 'COLE_COD_DANE_SEDE',
'COLE_COD_MCPIO_UBICACION', 'OHE_M', 'OHE_Estrato 2', 'OHE_Estrato 3',
'OHE_Estrato 4', 'OHE_Estrato 5', 'OHE_Estrato 6',
...
'OHE_Todos o casi todos los días', 'OHE_3 a 5 veces por semana',
'OHE_Nunca o rara vez comemos eso', 'OHE_Todos o casi todos los días',
'OHE_Entre 11 y 20 horas', 'OHE_Entre 21 y 30 horas',
'OHE_Menos de 10 horas', 'OHE_Más de 30 horas',
'FAMI_TIENECOMPUTADOR_Si', 'FAMI_TIENEINTERNET_Si'],
dtype='object', length=109)Python
# Dividir los datos en conjuntos de entrenamiento y prueba
X = saber11_n.drop('PUNT_MATEMATICAS', axis=1)
y = saber11_n['PUNT_MATEMATICAS']Python
# Escalamos la variable charges para hacerla más estandar
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
#Los algoritmos de preprocessing de sklearn están preparados para convertir matrices por lo que tenemos que hacer una transformación de nuestra variable y
# ya que es una variable de tipo Series
# para ello hacemos un .to_numpy() que nos convierte la serie en un array y luego hacemos reshape (-1,1) que transforma un array de 1xn en una matriz de nx1
y = scaler.fit_transform(y.to_numpy().reshape(-1,1))
# Volvemos a transformar nuestra variable en un array de 1xn
y=y.reshape(1,-1)[0]Python
# Escalar los datos utilizando MaxAbsScaler
scaler = MaxAbsScaler()
X_scaled = scaler.fit_transform(X)
# preparamos train data y test data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=43)
# Reemplazar NaN con ceros
X_train = X_train.fillna(0)
X_test = X_test.fillna(0)Python
# Crear y entrenar el modelo de regresión lineal múltiple
regresion_lineal=LinearRegression()
regresion_lineal.fit(X_train, y_train)Python
# FASE VALIDACION
# predecimos los valores y para los datos usados en el entrenamiento
prediccion_entrenamiento = regresion_lineal.predict(X_train)
# calculamos el Error Cuadrático Medio (MSE = Mean Squared Error)
mse_hipot5_train = mean_squared_error(y_true = y_train, y_pred = prediccion_entrenamiento)
print('Error Cuadrático Medio (MSE) HIPO 1 TRAIN= ' + str(mse_hipot5_train))
# predecimos los valores y para los datos usados en el entrenamiento
prediccion_entrenamiento = regresion_lineal.predict(X_test)
# calculamos el Error Cuadrático Medio (MSE = Mean Squared Error)
mse_hipot5_test = mean_squared_error(y_true = y_test, y_pred = prediccion_entrenamiento)
print('Error Cuadrático Medio (MSE) HIPO 1 TEST= ' + str(mse_hipot5_test))salida
Error Cuadrático Medio (MSE) HIPO 1 TRAIN= 0.9305982848337508
Error Cuadrático Medio (MSE) HIPO 1 TEST= 0.9253285091410614Python
# Gráfico de residuos
residuos = y_test - prediccion_entrenamiento
plt.figure(figsize=(8, 6))
plt.scatter(prediccion_entrenamiento, residuos, color='blue', alpha=0.5)
plt.xlabel('Valores Predichos')
plt.ylabel('Residuos')
plt.title('Gráfico de Residuos')
plt.hlines(y=0, xmin=prediccion_entrenamiento.min(), xmax=prediccion_entrenamiento.max(), color='red', linestyle='--', lw=2)
plt.show()Python
# Importancia de las variables
importancia_variables = pd.DataFrame({'Variable': X.columns, 'Importancia': regresion_lineal.coef_})
importancia_variables = importancia_variables.sort_values(by='Importancia', ascending=False)
plt.figure(figsize=(40, 38))
sns.barplot(x='Importancia', y='Variable', data=importancia_variables)
plt.title('Importancia de las Variables')
plt.xlabel('Importancia')
plt.ylabel('Variable')
plt.show()