Redes neuronales¶


Clase3: Predicción de valores continuos¶


Autor: Luis Fernando Apáez Álvarez

Contenido¶

  • Regresión lineal
  • Implementación de una red neuronal
  • Modelos con más variables regresoras

En esta clase realizaremos la implementación de un modelo de red neuronal para predicción de un valor continuo. Para ello trabajaremos con el conjunto de datos iris:

In [98]:
import seaborn as sns

print('Conjuntos de datos disponibles en seaborn: ')
for _ in sns.get_dataset_names():
    print(_, end=', ')
Conjuntos de datos disponibles en seaborn: 
anagrams, anscombe, attention, brain_networks, car_crashes, diamonds, dots, dowjones, exercise, flights, fmri, geyser, glue, healthexp, iris, mpg, penguins, planets, seaice, taxis, tips, titanic, 
In [99]:
# cargamos el conjunto de datos iris
df = sns.load_dataset('iris')
df.head()
Out[99]:
sepal_length sepal_width petal_length petal_width species
0 5.1 3.5 1.4 0.2 setosa
1 4.9 3.0 1.4 0.2 setosa
2 4.7 3.2 1.3 0.2 setosa
3 4.6 3.1 1.5 0.2 setosa
4 5.0 3.6 1.4 0.2 setosa

Y consideraremos un dataframe con las correlaciones ntre dichas variables

In [100]:
df.corr(method='pearson')
Out[100]:
sepal_length sepal_width petal_length petal_width
sepal_length 1.000000 -0.117570 0.871754 0.817941
sepal_width -0.117570 1.000000 -0.428440 -0.366126
petal_length 0.871754 -0.428440 1.000000 0.962865
petal_width 0.817941 -0.366126 0.962865 1.000000

Notamos que petal_width con petal_length están altamente correlacionadas. Gráficamente

In [102]:
ax = df.plot.scatter(x='petal_width', y='petal_length', c='blue', grid=True)

Para la primera parte de esta clase trabajaremos únicamente con las dos variables anteriores

In [104]:
# seleccionamos solo las dos variables de interes
df_reducido = df[['petal_width', 'petal_length']]

Regresión lineal ¶

Lo que haremos inicialmente será implementar un modelo de regresión lineal simple, donde petal_width será la variable regresora y petal_length será la variable de respuesta. Después de ajustar el modelo de regresión con los datos de entrenamiento, realizaremos predicciones sobre el conjunto de prueba. Para ello

División de los datos¶

In [107]:
# Importacion necesaria
from sklearn.model_selection import train_test_split

# definimos las variables
X = df['petal_width'].values.reshape(-1,1)
y = df['petal_length'].values.reshape(-1,1)

# division de los datos
X_train, X_test, y_train, y_test = train_test_split(X, y, # conjunto completo
                                       test_size=0.25,    # 25% para pruebas
                                       random_state=123)  # semilla aleatoria  

Procedemos a realizar el modelo de regresión y el ajuste

In [108]:
from sklearn.linear_model import LinearRegression

# instanciamos
reg = LinearRegression()

# ajustamos sobre los datos de entrenamiento
reg.fit(X_train, y_train)
Out[108]:
LinearRegression()
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
LinearRegression()

Realizamos ahora la predicción sobre el conjunto de pruebas y comparamos resultados mediante un dataframe

In [111]:
# predicion
y_pred_regression = reg.predict(X_test)

# dataframe con la informacion
df_info = pd.DataFrame(y_pred_regression).rename(columns = {0: 'y_pred_reg'})
df_info['y_test'] = y_test
df_info = df_info.reset_index()
# calculamos las diferencias entre los valores reales y los predichos
df_info['diff'] = abs(df_info.y_pred_reg - df_info.y_test)
# calculamos el porcentaje de error para cada fila
df_info['error'] = (df_info['diff'] * 100) / df_info['y_test']
df_info.head()
Out[111]:
index y_pred_reg y_test diff error
0 0 4.409119 4.9 0.490881 10.017988
1 1 5.736517 5.5 0.236517 4.300308
2 2 5.957750 5.6 0.357750 6.388392
3 3 3.966653 4.1 0.133347 3.252378
4 4 1.311856 1.4 0.088144 6.296008

Veamos un dataframe con estadísticas sobre la información anterior

In [112]:
df_info.describe()
Out[112]:
index y_pred_reg y_test diff error
count 38.000000 38.000000 38.000000 38.000000 38.000000
mean 18.500000 3.489255 3.544737 0.356043 11.113797
std 11.113055 1.801369 1.911374 0.264684 6.819835
min 0.000000 1.311856 1.100000 0.002953 0.089495
25% 9.250000 1.533089 1.425000 0.133154 6.319104
50% 18.500000 3.856036 4.050000 0.274186 9.833552
75% 27.750000 5.072818 5.075000 0.506806 14.613545
max 37.000000 6.178983 6.700000 1.078983 31.703670

Tenemos que el error porcentual (el referente a la columna error) fue en promedio del 11.11%; el error máximo fue del 31.7% y el mínimo del 0.08%. El 75% de los errores fue menor al 14.61% y el 50% de los errores fue menor al 9.83%. De tal manera, parece ser que el ajuste de la regresión sobre los datos fue muy bueno. Podemos comprobar dicho rendimiento mediante las siguientes métricas

In [114]:
from sklearn.metrics import mean_squared_error
from sklearn.metrics import r2_score

# error cuadratico medio
mse = mean_squared_error(y_pred_regression, y_test)
# R^2
r2 = r2_score(y_pred_regression, y_test)
# veamos
print(f'mse = {mse}\nR^2 = {r2}')
mse = 0.19498031795213722
R^2 = 0.9382883033472239

tenemos que el mse es pequeño y la $R^{2}$ es cercana a 1, de donde tenemos que el modelo de regresión obtenido es muy bueno.

Podemos ver un gráfico para observar qué tan buenas fueron nuestras predicciones. Para ello realizaremos un gráfico de líneas como sigue:

In [115]:
plt.plot(df_info.index, df_info.y_pred_reg, color='blue', label='prediccioón')
plt.plot(df_info.index, df_info.y_test, color='red', label='real')
plt.legend()
plt.grid()
plt.show()

Podemos observar un ajuste muy bueno de la predicción a los valores reales.

Lo que haremos después será la implementación de una red neuronal para predecir los valores de la variable petal_length.

Implementación de una red neuronal ¶

En esta ocasión utilizaremos sólo la función de activación ReLu:

$$ ReLu(x)=max(0, x) $$

dado que querremos mantener los valores continuos que le vayamos pasando a la red. Por ejemplo, no sería conveniente utilizar la función de activación sigmoide debido a que ésta se utiliza para problemas de clasificación binaria.

Además, para problemas de predición de valores continuas, es común utilizar la función de pérdida del error cuadrático medio.

De tal manera, definimos la siguiente función:

In [154]:
from keras.models import Sequential
from keras.layers import Dense

def modelo(n1, n2, activacion, epocas, boolean):
    """
    n1: número de neuronas en la primer capa
    n2: número de neuronas en la segunda capa
    activacion: función de activación en la última capa
    epocas: número de épocas
    boolean: booleano para determinar el valor de verbose
    """
    # Instanciamos el modelo
    model = Sequential()
    # Capa de entrada de 1 neurona y capa oculta de n1 neuronas.
    # Para la capa oculta utilizamos la funcion de activacion relu
    model.add(Dense(n1, activation='relu', input_shape=(1,)))
    # Capa oculta 2:
    # n2 neuronas y funcion de activacion relu
    model.add(Dense(n2, activation='relu'))
    # Capa de salida con funcion de activacion "activacion"
    model.add(Dense(1, activation=activacion))
    # Compilacion. Utilizaremos ahora el error cuadratico medio
    model.compile(optimizer='adam', loss='mean_squared_error')
    # Entrenamiento
    modelo = model.fit(X_train, y_train, epochs=epocas, verbose = boolean)
    # prediccion
    y_pred = model.predict(X_test)
    # dataframe con la informacion
    df = pd.DataFrame(y_pred).rename(columns = {0: 'y_pred'})
    df['y_test'] = y_test
    df = df.reset_index()
    df['diff'] = abs(df.y_pred - df.y_test)
    df['error'] = (df['diff'] * 100) / df['y_test']
    # estadisticas
    df_stats = df.describe()
    # grafica
    plt.plot(df.index, df.y_pred, color='blue', label='prediccioón')
    plt.plot(df.index, df.y_test, color='red', label='real')
    plt.legend()
    plt.grid()
    plt.show()
    # MSE
    mse = mean_squared_error(y_pred, y_test)
    print(f'mse = {mse}')
    return modelo, df, df_stats

Implementamos un primer modelo

In [156]:
modelo1, df1, df_stats1 = modelo(40, 25, 'relu', 13, True)
df_stats1
Epoch 1/13
4/4 [==============================] - 0s 2ms/step - loss: 16.4030
Epoch 2/13
4/4 [==============================] - 0s 2ms/step - loss: 15.8458
Epoch 3/13
4/4 [==============================] - 0s 2ms/step - loss: 15.3099
Epoch 4/13
4/4 [==============================] - 0s 3ms/step - loss: 14.7636
Epoch 5/13
4/4 [==============================] - 0s 2ms/step - loss: 14.2382
Epoch 6/13
4/4 [==============================] - 0s 2ms/step - loss: 13.6806
Epoch 7/13
4/4 [==============================] - 0s 2ms/step - loss: 13.0921
Epoch 8/13
4/4 [==============================] - 0s 2ms/step - loss: 12.4487
Epoch 9/13
4/4 [==============================] - 0s 2ms/step - loss: 11.8243
Epoch 10/13
4/4 [==============================] - 0s 2ms/step - loss: 11.1492
Epoch 11/13
4/4 [==============================] - 0s 2ms/step - loss: 10.4892
Epoch 12/13
4/4 [==============================] - 0s 2ms/step - loss: 9.8249
Epoch 13/13
4/4 [==============================] - 0s 2ms/step - loss: 9.0948
2/2 [==============================] - 0s 2ms/step
mse = 8.024392817825545
Out[156]:
index y_pred y_test diff error
count 38.000000 38.000000 38.000000 38.000000 38.000000
mean 18.500000 1.048651 3.544737 2.496086 70.268226
std 11.113055 0.575967 1.911374 1.357362 3.610582
min 0.000000 0.349918 1.100000 0.750082 62.309921
25% 9.250000 0.423397 1.425000 0.994972 67.671770
50% 18.500000 1.166187 4.050000 2.954499 69.757323
75% 27.750000 1.554964 5.075000 3.632096 73.297980
max 37.000000 1.908396 6.700000 4.862290 77.715922

con el cual obtenemos malos resultados.

Ahora, en vez de utilizar la función de activación ReLu utilizaremos la siguiente variante:

$$ LeakyReLU(x)=\left\{\begin{array}{c}x, x>0\\ \ 0, mx<0\end{array}\right. $$

donde ésta en vez de enviar valores negativos a cero utiliza un parámetro de pendiente muy pequeño que incorpora cierta información de valores negativos. El problema que tenía nuestra red neuronal era justamente ese, en el cual los valores negativos se estaban yendo todos a cero, problema el cual queda solucionado con la función de activación ReLU con fugas (o 𝐿𝑒𝑎𝑘𝑦𝑅𝑒𝐿𝑈). Un detalle importante por mencionar es que con la función de activación ReLu la convergencia es más rápida, no obstante, para la ReLu con fugas dicha convergencia será un poco más lenta, de modo que implementaremos un mayor número de épocas.

De tal manera escribiremos

In [157]:
modelo2, df2, df_stats2 = modelo(40, 25, 'LeakyReLU', 50, False)
df_stats2
2/2 [==============================] - 0s 2ms/step
mse = 0.19440326062005897
Out[157]:
index y_pred y_test diff error
count 38.000000 38.000000 38.000000 38.000000 38.000000
mean 18.500000 3.489606 3.544737 0.355140 11.158327
std 11.113055 1.794334 1.911374 0.264809 6.957903
min 0.000000 1.318692 1.100000 0.007195 0.218022
25% 9.250000 1.539637 1.425000 0.139637 5.891013
50% 18.500000 3.859528 4.050000 0.275254 9.974061
75% 27.750000 5.068981 5.075000 0.504230 14.585636
max 37.000000 6.162619 6.700000 1.062619 32.101742

con lo cual obtenemos mejores resultados, en realidad, dichos resultados son muy similares a los obtenidos con el modelo de regresión.

Recordemos que la función ReLu con fugas tiene un parámetro $m$ referente a la pendiente. Para modificar dicho valor podemos recurrir a tensorflow:

In [160]:
import tensorflow as tf

# ReLu con fugas configurando el valor de la pendiente m (alpha)
fun_activacion = lambda x: tf.keras.layers.LeakyReLU(alpha=x)

# alpha=0.3
modelo3, df3, df_stats3 = modelo(40, 25, fun_activacion(0.3), 50, False)
df_stats3
2/2 [==============================] - 0s 3ms/step
mse = 0.19706047023275194
Out[160]:
index y_pred y_test diff error
count 38.000000 38.000000 38.000000 38.000000 38.000000
mean 18.500000 3.454379 3.544737 0.348974 9.870676
std 11.113055 1.880185 1.911374 0.278051 6.661151
min 0.000000 1.181068 1.100000 0.012454 0.889572
25% 9.250000 1.412454 1.425000 0.150619 4.534514
50% 18.500000 3.837573 4.050000 0.285695 9.947510
75% 27.750000 5.107232 5.075000 0.509004 13.324466
max 37.000000 6.261467 6.700000 1.161467 25.660315

notamos que con dicho valor hemos mejorado el modelo en cuanto al error promedio, el valor del cuartil al 75% y el valor máximo del error ha disminuido, en comparativa con el modelo de regresión. Así, hemos obtenido un mejor modelo con la red neuronal.

Continuamos en la búsqueda por el mejor modelo

In [161]:
# alpha=0.4
modelo4, df4, df_stats4 = modelo(40, 25, fun_activacion(0.4), 50, False)
df_stats4
2/2 [==============================] - 0s 3ms/step
mse = 0.19659494009660292
Out[161]:
index y_pred y_test diff error
count 38.000000 38.000000 38.000000 38.000000 38.000000
mean 18.500000 3.451361 3.544737 0.347851 9.836075
std 11.113055 1.877487 1.911374 0.278636 6.686215
min 0.000000 1.179924 1.100000 0.011312 0.807965
25% 9.250000 1.411312 1.425000 0.147839 4.419739
50% 18.500000 3.838183 4.050000 0.285953 10.035467
75% 27.750000 5.102206 5.075000 0.509759 13.378070
max 37.000000 6.250940 6.700000 1.150940 25.720447
In [162]:
# alpha=0.7
modelo5, df5, df_stats5 = modelo(40, 25, fun_activacion(0.7), 50, False)
df_stats5
2/2 [==============================] - 0s 3ms/step
mse = 0.19503224669142566
Out[162]:
index y_pred y_test diff error
count 38.000000 38.000000 38.000000 38.000000 38.000000
mean 18.500000 3.486083 3.544737 0.355092 11.103247
std 11.113055 1.796349 1.911374 0.266092 6.860370
min 0.000000 1.314304 1.100000 0.002903 0.087982
25% 9.250000 1.534458 1.425000 0.134458 6.131354
50% 18.500000 3.855724 4.050000 0.270635 9.800012
75% 27.750000 5.065818 5.075000 0.509000 14.651458
max 37.000000 6.164742 6.700000 1.064742 31.696852

Al aumentar el valor de alpha en 0.7 tenemos un peor rendimiento comparado con el modelo donde alpha=0.4.

In [163]:
# alpha=0.4
modelo6, df6, df_stats6 = modelo(40, 25, fun_activacion(0.4), 70, False)
df_stats6
2/2 [==============================] - 0s 3ms/step
mse = 0.1948398463071247
Out[163]:
index y_pred y_test diff error
count 38.000000 38.000000 38.000000 38.000000 38.000000
mean 18.500000 3.465775 3.544737 0.351841 10.496029
std 11.113055 1.832457 1.911374 0.270126 6.207114
min 0.000000 1.249901 1.100000 0.021658 0.656296
25% 9.250000 1.474990 1.425000 0.146613 5.356446
50% 18.500000 3.841792 4.050000 0.263687 10.423440
75% 27.750000 5.077075 5.075000 0.514457 13.460788
max 37.000000 6.199116 6.700000 1.099116 28.404196

Tampoco parece ser lo correcto aumentar el número de épocas.

In [164]:
# alpha=0.4
modelo7, df7, df_stats7 = modelo(30, 20, fun_activacion(0.4), 70, False)
df_stats7
2/2 [==============================] - 0s 3ms/step
mse = 0.19387595750027908
Out[164]:
index y_pred y_test diff error
count 38.000000 38.000000 38.000000 38.000000 38.000000
mean 18.500000 3.467559 3.544737 0.350933 10.381939
std 11.113055 1.843523 1.911374 0.269506 6.190502
min 0.000000 1.239383 1.100000 0.019914 0.603461
25% 9.250000 1.464303 1.425000 0.139465 4.651673
50% 18.500000 3.847175 4.050000 0.275724 10.286566
75% 27.750000 5.088551 5.075000 0.507647 13.014203
max 37.000000 6.216816 6.700000 1.116816 27.876862

ni dismiuir el número de neuronas. Aunque en los modelos anterior no obtenemos como tal un mal modelo.

Obtamos entonces por quedarnos con el modelo 4:

In [165]:
df_stats4
Out[165]:
index y_pred y_test diff error
count 38.000000 38.000000 38.000000 38.000000 38.000000
mean 18.500000 3.451361 3.544737 0.347851 9.836075
std 11.113055 1.877487 1.911374 0.278636 6.686215
min 0.000000 1.179924 1.100000 0.011312 0.807965
25% 9.250000 1.411312 1.425000 0.147839 4.419739
50% 18.500000 3.838183 4.050000 0.285953 10.035467
75% 27.750000 5.102206 5.075000 0.509759 13.378070
max 37.000000 6.250940 6.700000 1.150940 25.720447

Recordemos que tanto la regresión lineal simple como el modelo de la red neurona solo ocuparon una variable con variable regresora. Lo que haremos ahora será la implementación de más variables predictorias. Así, la regresión lineal simple pasará a ser ahora una regresión lineal múltiple.

Modelos con más variables regresoras ¶

Regresión lineal múltiple¶

Para el caso de la regresión lineal simple únicamente consideramos una variable predictoria (petal_width). Luego, lo que ahoremos ahora será considerar 3 variables predictorias: sepal_length, sepal_width, petal_length.

Dado que efectuaremos también una regresión lineal, tendremos que dicha regresión será múltiple. En este caso mantendremos a petal_length como la variable de respuesta y consideraremos al resto (menos la variable species) como variables predictorias.

In [168]:
# Variables predictorias
X = df.drop(['petal_length', 'species'], axis=1).values
# variable de respuesta
y = df['petal_length'].values.reshape(-1,1)

# division de los datos
X_train, X_test, y_train, y_test = train_test_split(X, y, # conjunto completo
                                       test_size=0.25,    # 25% para pruebas
                                       random_state=123)  # semilla aleatoria  
# instanciamos
reg = LinearRegression()

# ajustamos sobre los datos de entrenamiento
reg.fit(X_train, y_train)
Out[168]:
LinearRegression()
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
LinearRegression()

De nuevo creamos un dataframe con los valores predichos y con los valores de y_test

In [169]:
# predicion
y_pred_regression = reg.predict(X_test)

# dataframe con la informacion
df_info = pd.DataFrame(y_pred_regression).rename(columns = {0: 'y_pred_reg'})
df_info['y_test'] = y_test
df_info = df_info.reset_index()
# calculamos las diferencias entre los valores reales y los predichos
df_info['diff'] = abs(df_info.y_pred_reg - df_info.y_test)
# calculamos el porcentaje de error para cada fila
df_info['error'] = (df_info['diff'] * 100) / df_info['y_test']
df_info.head()
Out[169]:
index y_pred_reg y_test diff error
0 0 4.910943 4.9 0.010943 0.223320
1 1 5.797656 5.5 0.297656 5.411921
2 2 5.776232 5.6 0.176232 3.147003
3 3 3.749124 4.1 0.350876 8.557963
4 4 1.092527 1.4 0.307473 21.962350

Vemos, en primera instancia, una mejora entorno a los valores de las primeras predicción. De manera más profunda veamos las estadísticas sobre la columna error

In [170]:
df_info.describe()
Out[170]:
index y_pred_reg y_test diff error
count 38.000000 38.000000 38.000000 38.000000 38.000000
mean 18.500000 3.513231 3.544737 0.261164 9.621598
std 11.113055 1.925357 1.911374 0.232472 9.685099
min 0.000000 1.054751 1.100000 0.005467 0.089624
25% 9.250000 1.492094 1.425000 0.058166 2.747729
50% 18.500000 3.802773 4.050000 0.190130 6.897631
75% 27.750000 4.906221 5.075000 0.363613 13.271660
max 37.000000 6.763899 6.700000 0.989029 35.823164

Notamos que el error promedio es menor en comparativa con el modelo de regresión lineal simple, aunque la desviación estándar y el error máximo aumentaron para el caso de la regresión lineal múltiple.

Veamos algunas métricas:

In [171]:
# error cuadratico medio
mse = mean_squared_error(y_pred_regression, y_test)
# R^2
r2 = r2_score(y_pred_regression, y_test)
# veamos
print(f'mse = {mse}\nR^2 = {r2}')
mse = 0.12082769704546548
R^2 = 0.9665245914976561

donde tenemos que:

métrica reg lineal simple reg lineal múltiple
$mse$ 0.1949 0.1208
$R^2$ 0.938 0.9665

es decir, tenemos mejores resultados con el modelo de regresión lineal múltiple. Finalemnte veamos el gráfico de los datos reales versus los predichos

In [172]:
plt.plot(df_info.index, df_info.y_pred_reg, color='blue', label='prediccioón')
plt.plot(df_info.index, df_info.y_test, color='red', label='real')
plt.legend()
plt.grid()
plt.show()

en el cual sí notamos una mejora en el ajuste comparando dicha gráfica con la obtenida en la regresión lineal simple:

aux1.png

Modelo de la red neuronal¶

Realizaremos un pequeño cambia para input_shape en la siguiente función

In [173]:
def modelo(n1, n2, activacion, epocas, boolean):
    """
    n1: número de neuronas en la primer capa
    n2: número de neuronas en la segunda capa
    activacion: función de activación en la última capa
    epocas: número de épocas
    boolean: booleano para determinar el valor de verbose
    """
    # Instanciamos el modelo
    model = Sequential()
    # Capa de entrada de 1 neurona y capa oculta de n1 neuronas.
    # Para la capa oculta utilizamos la funcion de activacion relu
    model.add(Dense(n1, activation='relu', input_shape=(3,)))
    # Capa oculta 2:
    # n2 neuronas y funcion de activacion relu
    model.add(Dense(n2, activation='relu'))
    # Capa de salida con funcion de activacion "activacion"
    model.add(Dense(1, activation=activacion))
    # Compilacion. Utilizaremos ahora el error cuadratico medio
    model.compile(optimizer='adam', loss='mean_squared_error')
    # Entrenamiento
    modelo = model.fit(X_train, y_train, epochs=epocas, verbose = boolean)
    # prediccion
    y_pred = model.predict(X_test)
    # dataframe con la informacion
    df = pd.DataFrame(y_pred).rename(columns = {0: 'y_pred'})
    df['y_test'] = y_test
    df = df.reset_index()
    df['diff'] = abs(df.y_pred - df.y_test)
    df['error'] = (df['diff'] * 100) / df['y_test']
    # estadisticas
    df_stats = df.describe()
    # grafica
    plt.plot(df.index, df.y_pred, color='blue', label='prediccioón')
    plt.plot(df.index, df.y_test, color='red', label='real')
    plt.legend()
    plt.grid()
    plt.show()
    # MSE
    mse = mean_squared_error(y_pred, y_test)
    print(f'mse = {mse}')
    return modelo, df, df_stats

pues recordemos que ahora estamos trabajando con 3 variables predictorias. Luego, implementamos los mismos valores configurados en el modelo 4

In [187]:
# Para este caso aumentamos el numero de epocas
modelo1_mult, df1_mult, df_stats1_mult = modelo(40, 25, fun_activacion(0.4), 70, False)
df_stats1_mult
2/2 [==============================] - 0s 3ms/step
mse = 0.11747747303302854
Out[187]:
index y_pred y_test diff error
count 38.000000 38.000000 38.000000 38.000000 38.000000
mean 18.500000 3.527997 3.544737 0.253141 8.675280
std 11.113055 1.903661 1.911374 0.234180 8.862192
min 0.000000 1.136449 1.100000 0.017433 0.355767
25% 9.250000 1.475468 1.425000 0.051992 2.398264
50% 18.500000 3.828365 4.050000 0.169351 6.640920
75% 27.750000 4.959173 5.075000 0.377703 10.674295
max 37.000000 6.720815 6.700000 0.962185 33.820804

Notamos también una mejora respecto al resultado obtenido en el modelo 4 (en el cual solo trabajamos con una variable predictoria):

aux2.png

Podemos comparar estadísticas del modelo 4 con una variable predictoria, al modelo implementado antes con 3 variables predictorias

In [188]:
display(df_stats4)
print()
display(df_stats1_mult)
index y_pred y_test diff error
count 38.000000 38.000000 38.000000 38.000000 38.000000
mean 18.500000 3.451361 3.544737 0.347851 9.836075
std 11.113055 1.877487 1.911374 0.278636 6.686215
min 0.000000 1.179924 1.100000 0.011312 0.807965
25% 9.250000 1.411312 1.425000 0.147839 4.419739
50% 18.500000 3.838183 4.050000 0.285953 10.035467
75% 27.750000 5.102206 5.075000 0.509759 13.378070
max 37.000000 6.250940 6.700000 1.150940 25.720447

index y_pred y_test diff error
count 38.000000 38.000000 38.000000 38.000000 38.000000
mean 18.500000 3.527997 3.544737 0.253141 8.675280
std 11.113055 1.903661 1.911374 0.234180 8.862192
min 0.000000 1.136449 1.100000 0.017433 0.355767
25% 9.250000 1.475468 1.425000 0.051992 2.398264
50% 18.500000 3.828365 4.050000 0.169351 6.640920
75% 27.750000 4.959173 5.075000 0.377703 10.674295
max 37.000000 6.720815 6.700000 0.962185 33.820804

notamos mejoras en el modelo modelo1_mult, pero el modelo 4 mantiene un menor número referente a la desviacón estándar y al error máximo cometido. De tal manera vemos que cada modelo tendrá sus ventajas y desventajas.