blogs
Saber 11 · Regresión lineal múltiple

Ciencia de Datos

Saber 11 · Regresión lineal múltiple

Normalización de variables, entrenamiento y validación de un modelo de regresión lineal múltiple sobre el puntaje de matemáticas, con residuos e importancia de variables.

27 jun 2024

6 min

HomeBlogsSaber 11 · Regresión lineal múltiple

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, MaxAbsScaler
Python
# 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
PERIODOPUNT_MATEMATICASESTU_GENEROFAMI_TIENECOMPUTADORFAMI_TIENEINTERNETFAMI_ESTRATOVIVIENDACOLE_COD_DANE_SEDECOLE_COD_MCPIO_UBICACIONCOLE_NATURALEZAFAMI_EDUCACIONPADRE...FAMI_TIENELAVADORAFAMI_TIENEHORNOMICROOGASFAMI_TIENEAUTOMOVILFAMI_TIENEMOTOCICLETAFAMI_TIENECONSOLAVIDEOJUEGOSFAMI_COMELECHEDERIVADOSFAMI_COMECARNEPESCADOHUEVOFAMI_COMECEREALFRUTOSLEGUMBREESTU_HORASSEMANATRABAJACOLE_JORNADA
02018146FSiSiEstrato 331900100233019001NO OFICIALSecundaria (Bachillerato) completa...SiSiNoNoNoTodos o casi todos los díasTodos o casi todos los días3 a 5 veces por semana0MAÑANA
12018162MSiSiEstrato 431900100233019001NO OFICIALEducación profesional completa...SiSiSiSiSiTodos o casi todos los díasTodos o casi todos los días1 o 2 veces por semana0MAÑANA
22018143FNoNoEstrato 131900100233019001NO OFICIALSecundaria (Bachillerato) completa...NoNoNoNoNoTodos o casi todos los díasNunca o rara vez comemos esoTodos o casi todos los días0MAÑANA
32018175MSiNoEstrato 131900100233019001NO OFICIALPrimaria completa...NoSiSiNoSiTodos o casi todos los díasTodos o casi todos los díasNunca o rara vez comemos eso0MAÑANA
42018162FSiSiEstrato 231900100233019001NO OFICIALTécnica o tecnológica completa...NoNoNoNoNoTodos o casi todos los días3 a 5 veces por semana1 o 2 veces por semana0MAÑANA
..................................................................
27752772023438FNoSiEstrato 211744400081817444OFICIALPrimaria completa...NoNoNoNoNo1 o 2 veces por semanaTodos o casi todos los días1 o 2 veces por semana0UNICA
27752782023448FNoSiEstrato 111744400081817444OFICIALSecundaria (Bachillerato) completa...SiNoNoSiNo3 a 5 veces por semanaNunca o rara vez comemos esoTodos o casi todos los días0UNICA
27752792023461FNoNoEstrato 117328300003873283OFICIALPrimaria completa...SiNoNoNoNo1 o 2 veces por semana3 a 5 veces por semanaNunca o rara vez comemos eso0UNICA
27752802023473FSiSiEstrato 317328300003873283OFICIALEducación profesional completa...SiSiSiNoNo3 a 5 veces por semanaTodos o casi todos los días3 a 5 veces por semana0UNICA
27752812023443FNoNoEstrato 122380700283923807OFICIALSecundaria (Bachillerato) completa...SiNoNoSiNo1 o 2 veces por semana1 o 2 veces por semana3 a 5 veces por semana0UNICA

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
PERIODOPUNT_MATEMATICASCOLE_COD_DANE_SEDECOLE_COD_MCPIO_UBICACIONOHE_MOHE_Estrato 2OHE_Estrato 3OHE_Estrato 4OHE_Estrato 5OHE_Estrato 6...OHE_Todos o casi todos los díasOHE_3 a 5 veces por semanaOHE_Nunca o rara vez comemos esoOHE_Todos o casi todos los díasOHE_Entre 11 y 20 horasOHE_Entre 21 y 30 horasOHE_Menos de 10 horasOHE_Más de 30 horasFAMI_TIENECOMPUTADOR_SiFAMI_TIENEINTERNET_Si
266201817431100104266711001100001...1001000011
267201817831100104266711001000000...0000000000
268201817831100104266711001000010...1100000011
269201816031100104266711001000100...0001000010
270201816331100104266711001000001...1100000011
..................................................................
2775242202344431100100545111001000000...1100000011
2775259202342511100104438511001100000...0000000000
2775260202344111100101092811001100000...0000000000
2775264202342611100104438511001100000...0000000000
2775267202343311100104438511001100000...0000000000

423240 rows × 109 columns

Revisamos las nuevas columnas añadidas recientemente.

Python
saber11_n.columns
salida
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.9253285091410614
Python
# 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()