Documentos de Académico
Documentos de Profesional
Documentos de Cultura
En este taller guiado haremos un acercamiento básico a varios de los pasos más
importantes del aprendizaje computacional usando la librería especializada Scikit-learn.
Veremos cómo:
cargar conjuntos de datos.
preprocesar datos numéricos y categóricos.
crear particiones de datos entrenamiento - prueba.
entrenar modelos (regresión logística) para clasificación.
evaluar el desempeño de modelos para clasificación.
1. Importar scikit-learn
Scikit-learn es una librería especializada de aprendizaje computacional para el lenguaje de
programación Python. Cuenta con múltiples paquetes y submódulos que serán importados
en sus respectivas secciones.
El paquete de Python de Scikit-learn de pip se debe instalar/actualizar con el nombre
scikit-learn :
file:///Users/mac/Downloads/M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn.html 1/26
4/5/23, 18:44 M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn
Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-w
heels/public/simple/
Requirement already satisfied: scikit-learn in /usr/local/lib/python3.10/dist-
packages (1.2.2)
Requirement already satisfied: numpy>=1.17.3 in /usr/local/lib/python3.10/dist
-packages (from scikit-learn) (1.22.4)
Requirement already satisfied: threadpoolctl>=2.0.0 in /usr/local/lib/python3.
10/dist-packages (from scikit-learn) (3.1.0)
Requirement already satisfied: joblib>=1.1.1 in /usr/local/lib/python3.10/dist
-packages (from scikit-learn) (1.2.0)
Requirement already satisfied: scipy>=1.3.2 in /usr/local/lib/python3.10/dist-
packages (from scikit-learn) (1.10.1)
La manera en que importe los paquetes y funciones es una elección personal. Por ejemplo,
puede decidir importar todas las definiciones de un paquete:
In [3]: # Importa todas las definiciones dentro del submódulo "sklearn.datasets"
from sklearn.datasets import *
iris = load_iris()
iris = load_iris
iris = datasets.load_iris()
import numpy as np
import pandas as pd
import matplotlib as mpl
!python --version
file:///Users/mac/Downloads/M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn.html 2/26
4/5/23, 18:44 M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn
print('NumPy', np.__version__)
print('Pandas', pd.__version__)
print('Matplotlib', mpl.__version__)
print('Scikit-learn', sklearn.__version__)
Python 3.10.11
NumPy 1.22.4
Pandas 1.5.3
Matplotlib 3.7.1
Scikit-learn 1.2.2
2. Cargar datos
Los modelos de Scikit-learn aceptan datos numéricos almacenados en arreglos de Numpy o
en matrices dispersas de Scipy. Otros tipos de datos convertibles a arreglos de Numpy
también son aceptados, como listas y DataFrames de Pandas.
Scikit-learn ofrece funciones de utilidad para cargar una pequeña colección de populares
conjuntos de datos, además de ofrecer funciones de utilidad para generar conjuntos de
datos sintéticos.
2.1. Conjuntos de datos
Scikit-learn ofrece funciones de utilidad en el paquete datasets para cargar conjuntos de
datos populares, los cuales suelen ser usados para evaluar el desempeño de algoritmos de
aprendizaje computacional. Estos conjuntos de datos suelen ser llamados "conjuntos de
juguete" o benchmark.
2.1.1. Loaders
En el caso de conjuntos de datos pequeños, scikit-learn cuenta con una familia de
funciones llamada loaders. Estos conjuntos de datos vienen incluidos con la instalación de
scikit-learn y no implican un uso de red adicional para descargarlos.
Por ejemplo, veamos uno de los conjuntos de datos más populares: el conjunto de datos de
la familia de flores Iris. Usaremos la función sklearn.datasets.load_iris :
file:///Users/mac/Downloads/M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn.html 3/26
4/5/23, 18:44 M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn
iris = datasets.load_iris()
print(type(iris))
<class 'sklearn.utils._bunch.Bunch'>
Las llaves pueden ser accedidas a través de llaves cuadradas ( [] ) o como un atributo a
través de la notación con punto ( . ).
In [ ]: # Las dos líneas de código retornan lo mismo.
print(iris.feature_names)
print(iris['feature_names'])
['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (c
m)']
['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (c
m)']
['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (c
m)']
En general, las feature o características hacen referencia a las variables que usaremos para
entrenar nuestros modelos de aprendizaje computacional y predecir el target u objetivo,
también llamado etiqueta.
file:///Users/mac/Downloads/M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn.html 4/26
4/5/23, 18:44 M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn
(150, 4)
(150,)
Como acabamos de ver, el conjunto de datos Iris cuenta con ejemplos y 150 4
características.
Por ejemplo, si quisiéramos saber las características de unos ejemplos y su etiqueta
podemos hacer lo siguiente:
In [ ]: # Lista de ids de los ejemplos que vamos a consultar
ids = [0, 25, 50, 100]
for i in ids:
print(f'Ejemplo: {i}')
print(f'Características: {iris.data[i]}, etiqueta: {iris.target[i]}\n')
file:///Users/mac/Downloads/M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn.html 5/26
4/5/23, 18:44 M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn
Ejemplo: 0
Características: [5.1 3.5 1.4 0.2], etiqueta: 0
Ejemplo: 25
Características: [5. 3. 1.6 0.2], etiqueta: 0
Ejemplo: 50
Características: [7. 3.2 4.7 1.4], etiqueta: 1
Ejemplo: 100
Características: [6.3 3.3 6. 2.5], etiqueta: 2
Nombres de las características: ['sepal length (cm)', 'sepal width (cm)', 'pet
al length (cm)', 'petal width (cm)']
Nombres de las etiquetas: ['setosa' 'versicolor' 'virginica']
Usualmente, se tratará de convertir los datos que se tengan a este formato, con el objetivo
de tenerlos listos para ser preprocesados y procesados por un algoritmo de aprendizaje
computacional.
Por ejemplo, para obtener Iris en el formato X, y podríamos hacer lo siguiente:
In [ ]: # Desempaquetado de tuplas a partir de los atributos.
X, y = iris.data, iris.target
file:///Users/mac/Downloads/M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn.html 6/26
4/5/23, 18:44 M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn
2.1.2. Fetchers
En el caso de conjuntos de datos más grandes, scikit-learn ofrece la familia de funciones
fetchers. Estos conjuntos de datos no están incluidos en la instalación de scikit-learn y
deben ser descargados con recursos de red.
Al ejecutar la siguiente celda notará que se hará un llamado para descargar el conjunto de
datos california housing (regresión).
In [ ]: # Los Fetcher también hacen parte del submódulo sklearn.datasets.
from sklearn import datasets
In [ ]: print(type(california_housing))
<class 'sklearn.utils._bunch.Bunch'>
mpl.rcParams['figure.dpi'] = 110
file:///Users/mac/Downloads/M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn.html 7/26
4/5/23, 18:44 M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn
file:///Users/mac/Downloads/M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn.html 8/26
4/5/23, 18:44 M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn
file:///Users/mac/Downloads/M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn.html 9/26
4/5/23, 18:44 M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn
Los conjuntos de datos generados de esta manera son generados de manera aleatoria, es
decir, en cada ocasión será generado un conjunto de datos potencialmente distinto.
Para generar el mismo conjunto de datos puede fijar la semilla con el argumento
random_state :
file:///Users/mac/Downloads/M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn.html 10/26
4/5/23, 18:44 M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn
Podemos ver información general del conjunto de datos con el método info de Pandas:
In [ ]: titanic_df.info()
file:///Users/mac/Downloads/M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn.html 11/26
4/5/23, 18:44 M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 PassengerId 891 non-null int64
1 Survived 891 non-null int64
2 Pclass 891 non-null int64
3 Name 891 non-null object
4 Sex 891 non-null object
5 Age 714 non-null float64
6 SibSp 891 non-null int64
7 Parch 891 non-null int64
8 Ticket 891 non-null object
9 Fare 891 non-null float64
10 Cabin 204 non-null object
11 Embarked 889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB
print(df_nona.shape)
(712, 10)
print(X.shape)
print(y.shape)
(712, 9)
(712,)
Podemos ver que el conjunto de datos resultante tiene ejemplos con características.
712 9
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.series.Series'>
Primero veamos como convertir un objeto de Pandas a un arreglo de NumPy, esto se logra
con el atributo values de un DataFrame o una Serie.
In [ ]: # .values retorna un arreglo de NumPy.
y = y.values
Las variables numéricas del conjunto de datos son: Age , SibSp , Parch , y Fare .
In [ ]: numeric = ['Age', 'SibSp', 'Parch', 'Fare']
print(X_numeric.shape)
print(type(X_numeric))
(712, 4)
<class 'numpy.ndarray'>
file:///Users/mac/Downloads/M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn.html 13/26
4/5/23, 18:44 M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn
Ejemplo 0:
Variables: [22. 1. 0. 7.25]
Etiqueta: 0
Ejemplo 1:
Variables: [38. 1. 0. 71.2833]
Etiqueta: 1
Ejemplo 2:
Variables: [26. 0. 0. 7.925]
Etiqueta: 1
Ejemplo 3:
Variables: [35. 1. 0. 53.1]
Etiqueta: 1
Ejemplo 4:
Variables: [35. 0. 0. 8.05]
Etiqueta: 0
No tendremos en cuenta Name y Ticket para el siguiente ejemplo por su gran cantidad
de valores posibles. En este caso usaremos solamente las variables Pclass , Sex y
Embarked .
print(X_categoric.shape)
print(type(X_categoric))
(712, 3)
<class 'numpy.ndarray'>
for i in ids:
print(f'Ejemplo {i}:')
print('Variables:', X_categoric[i])
print('Etiqueta:', y[i])
print()
Ejemplo 0:
Variables: [3 'male' 'S']
Etiqueta: 0
Ejemplo 1:
Variables: [1 'female' 'C']
Etiqueta: 1
Ejemplo 15:
Variables: [3 'male' 'Q']
Etiqueta: 0
Ejemplo 20:
Variables: [1 'male' 'S']
Etiqueta: 1
Pclass .
Los valores male y female corresponden a la variable Sex (género de la persona).
Los valores S , C y Q corresponden a la variable Embarked . Estos indican el puerto
de embarque que utilizó la persona, donde C = Cherbourg , Q = Queenstown y S
= Southampton .
3. Preprocesamiento
Scikit-learn expone el paquete preprocessing el cual contiene una serie de
transformaciones para variables numéricas tanto como categóricas.
La importancia del preprocesamiento radica en que puede potencialmente mejorar (o
empeorar) el desempeño de los algoritmos de aprendizaje computacional. En el caso de
variables categóricas para el caso de Scikit-learn no pueden ser usadas sin aplicar un
preprocesamiento.
Las transformaciones de Scikit-learn son fáciles de usar. Estas implementan la interfaz
Transformer , la cual expone los 3 siguientes métodos:
file:///Users/mac/Downloads/M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn.html 15/26
4/5/23, 18:44 M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn
3.1.1. StandardScaler
Veamos primero StandardScaler :
Este permite aplicar la transformación:
X − μ
′
X =
σ
Donde:
: Media aritmética de los datos.
μ
estándar de . 1
In [ ]: for i in range(3):
print('Ejemplo:', i)
print('Original: ', X_numeric[i])
print('Estandarizado: ', X_numeric_standarized[i])
print()
Ejemplo: 0
Original: [22. 1. 0. 7.25]
Estandarizado: [-0.52766856 0.52251079 -0.50678737 -0.51637992]
Ejemplo: 1
Original: [38. 1. 0. 71.2833]
Estandarizado: [ 0.57709388 0.52251079 -0.50678737 0.69404605]
Ejemplo: 2
Original: [26. 0. 0. 7.925]
Estandarizado: [-0.25147795 -0.55271372 -0.50678737 -0.50362035]
3.1.2. MinMaxScaler
MinMaxScaler permite escalar los datos a un rango específico, es decir, si una
característica se encuentra en el rango [min(X), max(X)] y el argumento
feature_range = (0, 1) , entonces cada valor será escalado de tal manera que esté
en el rango [0, 1] .
In [ ]: from sklearn.preprocessing import MinMaxScaler
Ejemplo: 0
Original: [22. 1. 0. 7.25]
MinMax: [0.27117366 0.2 0. 0.01415106]
Ejemplo: 1
Original: [38. 1. 0. 71.2833]
MinMax: [0.4722292 0.2 0. 0.13913574]
Ejemplo: 2
Original: [26. 0. 0. 7.925]
MinMax: [0.32143755 0. 0. 0.01546857]
file:///Users/mac/Downloads/M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn.html 17/26
4/5/23, 18:44 M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn
(0.0, 1.0)
Out[ ]:
Asumiendo que un ejemplo tiene el -ésimo valor posible de la variable original, se procesa
j
de la siguiente manera:
Se asigna 1 en la posición . j
Se asigna 0 al resto.
La variable Embarked tiene los siguientes valores únicos: S, C, Q .
Lo verificamos con el método unique de NumPy.
In [ ]: import numpy as np
Embarked
C
Se transformarían de la siguiente manera:
S C Q
1 0 0
0 1 0
0 0 1
0 1 0
One Hot Encoding se puede de usar de manera muy sencilla en Scikit-learn con el método
OneHotEncoder :
Por defecto OneHotEncoder retorna matrices sparse de SciPy, una implementación que
mejora el desempeño de las operaciones matriciales cuando se tienen muchas entradas de
una matriz en (¡perfecto para One Hot Encoding!).
0
(712, 8)
<class 'numpy.ndarray'>
/usr/local/lib/python3.9/dist-packages/sklearn/preprocessing/_encoders.py:868:
FutureWarning: `sparse` was renamed to `sparse_output` in version 1.2 and will
be removed in 1.4. `sparse_output` is ignored unless you leave `sparse` to its
default value.
warnings.warn(
Cómo podemos ver, la variable Sex con valores únicos, la variable Pclass con
2 3
file:///Users/mac/Downloads/M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn.html 19/26
4/5/23, 18:44 M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn
Ejemplo: 0
Original: [3 'male' 'S']
One Hot: [0. 0. 1. 0. 1. 0. 0. 1.]
Ejemplo: 1
Original: [1 'female' 'C']
One Hot: [1. 0. 0. 1. 0. 1. 0. 0.]
Ejemplo: 15
Original: [3 'male' 'Q']
One Hot: [0. 0. 1. 0. 1. 0. 1. 0.]
Ejemplo: 20
Original: [1 'male' 'S']
One Hot: [1. 0. 0. 0. 1. 0. 0. 1.]
(columnas).
In [ ]: import numpy as np
(712, 12)
4. Entrenamiento de modelos
En esta sección entrenaremos dos modelos de regresión logística.
Uno utilizando solo las variables numéricas preprocesadas.
Otro usando las variables numéricas y categóricas, ambas preprocesadas.
Generalmente los algoritmos de aprendizaje computacional son entrenados en una partición
de entrenamiento (train) y probados en una partición de datos de prueba (test).
Los datos de entrenamiento son aquellos datos de los cuales el algoritmo aprende.
Los datos de prueba son aquellos que se usan para estimar el desempeño del
algoritmo en datos desconocidos por el modelo.
Las particiones NO deben compartir datos. Con ayuda de scikit-learn podemos crear
particiones de entrenamiento y prueba para hacer esto fácilmente.
4.1. Partición de entrenamiento y prueba
file:///Users/mac/Downloads/M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn.html 20/26
4/5/23, 18:44 M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn
Tenga en cuenta que usted le puede poner cualquier nombre a las variables que retorna
train_test_split, lo anterior es solo una convención.
Usando el parámetro test_size podemos indicar, con un número entre 0 y 1, el
porcentaje de datos que deseamos usar para la partición de prueba.
Un ejemplo básico de uso, con de los datos para pruebas y para entrenamiento
30% 70%
sería el siguiente:
X_train, X_test, y_train, y_test = train_test_split(X, y,
test_size=0.3)
En nuestro caso le indicamos a train_test_split que utilice el de los datos como 30%
True
True
4.2. Entrenamiento
Debido a que el conjunto de datos Titanic plantea un problema de clasificación
(supervivencia), usaremos un modelo de clasificación lineal llamado regresión logística.
Los modelos de clasificación buscan discernir el grupo al que pertenece un ejemplo (i.e.,
predecir su etiqueta).
Un modelo de clasificación recibe un conjunto de variables x (características) y produce
una salida y (etiqueta) la cual es la predicción del modelo.
La salida de un modelo de clasificación suele estar codificada como un número. El numero
está asociado a la clase (que el modelo predice) que pertenece el ejemplo.
Utilizaremos el modelo generado por la función LogisticRegression del paquete
linear_model de Scikit-learn.
In [ ]: clf_numeric = linear_model.LogisticRegression(random_state=2)
In [ ]: clf_numeric.fit(X_train_num, y_train)
Out[ ]: ▾ LogisticRegression
LogisticRegression(random_state=2)
Utilizamos fit pero esta vez con X_train_full , la matriz con las características tanto
numéricas como categóricas de la partición de entrenamiento.
In [ ]: clf_full.fit(X_train_full, y_train)
Out[ ]: ▾ LogisticRegression
LogisticRegression(random_state=2)
5. Evaluación
file:///Users/mac/Downloads/M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn.html 23/26
4/5/23, 18:44 M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn
for i in range(5):
print(f'Predicho: {y_pred[i]}, Etiqueta: {y_test[i]}\n')
Predicho: 0, Etiqueta: 1
Predicho: 0, Etiqueta: 1
Predicho: 0, Etiqueta: 0
Predicho: 1, Etiqueta: 1
Predicho: 0, Etiqueta: 0
Como podemos ver, el modelo se equivoca en de los primeros ejemplos. Note que
2 5
predict acepta una matriz, un error común es tratar de usar predict con vectores.
file:///Users/mac/Downloads/M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn.html 24/26
4/5/23, 18:44 M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn
file:///Users/mac/Downloads/M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn.html 25/26
4/5/23, 18:44 M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn
Cómo podemos ver incluir las variables categóricas mejora el desempeño del mismo
algoritmo substancialmente.
En Titanic un indicador de supervivencia muy importante es el género, una proporción
mucho más grande de mujeres que de hombres sobrevivieron a la tragedia. Esto puede ser
utilizado para interpretar la mejora de desempeño del modelo.
Recursos adicionales
Los siguientes enlaces corresponden a sitios en donde encontrará información muy útil para
profundizar en el conocimiento de las funcionalidades de la librería Scikit-learn:
Scikit-learn - Datasets
Scikit-learn - Preprocessing
Scikit-learn - Linear models
Créditos
Profesor: Fabio Augusto Gonzalez
Asistentes docentes:
Miguel Angel Ortiz Marín
Alberto Nicolai Romero Martínez
Universidad Nacional de Colombia - Facultad de Ingeniería
In [ ]: !jupyter nbconvert --to html /content
file:///Users/mac/Downloads/M2U1_Introducción_al_Aprendizaje_Computacional_y_scikit_learn.html 26/26
7/5/23, 10:02 M2U2_Exploración_de_la_complejidad_y_el_sobreajuste
Complejidad y sobreajuste
En este notebook exploraremos la diferencia entre parámetros e hiperparámetros de un
modelo de aprendizaje computacional, además de conceptos como la capacidad o
complejidad, y las consecuencias del subajuste y sobreajuste.
Para esto, observaremos cómo se comporta la complejidad del modelo de clasificación no
lineal k-vecinos más cercanos (K-nearest neighbors en inglés).
1. Dependencias
Importamos las librerías necesarias y definimos algunas funciones básicas de visualización
que vamos a usar en algunos ejemplos.
1.1. Dependencias
Para la construcción de modelos y ejecución de procedimientos metodológicos de
aprendizaje automático, utilizaremos la librería Scikit-learn ( sklearn ) y varias de sus
funciones y conjuntos de datos.
In [ ]: # Actualizamos scikit-learn a la última versión
!pip install -U scikit-learn
# Importamos scikit-learn
import sklearn
file:///Users/mac/Downloads/M2U2_Exploración_de_la_complejidad_y_el_sobreajuste.html 1/21
7/5/23, 10:02 M2U2_Exploración_de_la_complejidad_y_el_sobreajuste
Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-w
heels/public/simple/
Requirement already satisfied: scikit-learn in /usr/local/lib/python3.9/dist-p
ackages (1.2.2)
Requirement already satisfied: threadpoolctl>=2.0.0 in /usr/local/lib/python3.
9/dist-packages (from scikit-learn) (3.1.0)
Requirement already satisfied: numpy>=1.17.3 in /usr/local/lib/python3.9/dist-
packages (from scikit-learn) (1.22.4)
Requirement already satisfied: scipy>=1.3.2 in /usr/local/lib/python3.9/dist-p
ackages (from scikit-learn) (1.10.1)
Requirement already satisfied: joblib>=1.1.1 in /usr/local/lib/python3.9/dist-
packages (from scikit-learn) (1.1.1)
Python 3.9.16
Scikit-learn 1.2.2
NumPy 1.22.4
Pandas 1.4.4
Matplotlib 3.7.1
Seaborn 0.12.2
Para ilustrar los ejemplos discutidos en este material utilizaremos algunas funciones que
permiten visualizar de manera general los datos y conceptos discutidos en las secciones.
Nota: Matplotlib y Seaborn se encuentran por fuera del alcance de este
módulo. No es necesario que entienda estas funciones en detalle para sacar
partido del resto del contenido puesto a su disposición. Usted decide si leer o
no estas funciones en profundidad. Si decide omitir esta sección, continúe
directamente con la siguiente sección, en donde se discutirán los conjuntos
de datos que vamos a utilizar.
In [ ]: # Función para visualizar un conjunto de datos de dos variables en un plano 2D
def plot_data(X, y, model = None, ax = None, title=None):
if ax is None:
_, ax = plt.subplots(dpi = 110)
y_unique = np.unique(y)
df = pd.DataFrame({'x1': X[:,0], 'x2': X[:,1], 'Clases': y})
sns.set_theme()
sns.scatterplot(data = df, x = 'x1', y = 'x2',
hue = 'Clases',style = 'Clases', ax = ax, palette = 'Set1')
ZZ = np.zeros((grid_r, grid_c))
for i in range(grid_r):
for j in range(grid_c):
ZZ[i, j] = pred_fun(XX[i, j], YY[i, j])
file:///Users/mac/Downloads/M2U2_Exploración_de_la_complejidad_y_el_sobreajuste.html 3/21
7/5/23, 10:02 M2U2_Exploración_de_la_complejidad_y_el_sobreajuste
def plot_learning_curve(train_error, generalization_error):
balance_point = np.array(generalization_error).argmin() + 1
plt.figure(figsize = (8, 5), dpi = 105)
Primeras 5 muestras:
[[ 2.17300137 0.68579369]
[ 1.97315415 0.28555497]
[-0.15360193 0.194076 ]
[-0.55760668 0.20288223]
[ 0.32028022 -0.44518473]]
Primeras 5 etiquetas: [1 1 0 1 1]
In [ ]: plot_data(X, y)
file:///Users/mac/Downloads/M2U2_Exploración_de_la_complejidad_y_el_sobreajuste.html 4/21
7/5/23, 10:02 M2U2_Exploración_de_la_complejidad_y_el_sobreajuste
3. Parámetros e Hiperparámetros
file:///Users/mac/Downloads/M2U2_Exploración_de_la_complejidad_y_el_sobreajuste.html 5/21
7/5/23, 10:02 M2U2_Exploración_de_la_complejidad_y_el_sobreajuste
1
^ =
y
1 + e−w⋅x+w0
In [ ]: # Definimos el modelo.
model_1 = LogisticRegression()
Este hiperparámetro afecta la forma del modelo, ya que tiene un parámetro menos.
Veamos la diferencia entre el comportamiento de los dos modelos definidos en el conjunto
de datos artificial blobs:
file:///Users/mac/Downloads/M2U2_Exploración_de_la_complejidad_y_el_sobreajuste.html 6/21
7/5/23, 10:02 M2U2_Exploración_de_la_complejidad_y_el_sobreajuste
In [ ]: # Entrenamos el modelo 1.
model_1.fit(X_blobs, y_blobs)
Out[ ]: ▾ LogisticRegression
LogisticRegression()
In [ ]: # Entrenamos el modelo 2.
model_2.fit(X_blobs, y_blobs)
Out[ ]: ▾ LogisticRegression
LogisticRegression(fit_intercept=False)
Podemos ver los parámetros de los dos modelos. Estos pueden ser accedidos con los
atributos coef_ (vector de pesos del modelo ) e intercept_ (intercepto ).
w w0
Como podemos ver, el segundo modelo tiene y esto afecta los valores del vector de
w0 = 0
A partir de la siguiente visualización podemos ver que la línea que separa las regiones de
decisión del modelo pasa por el punto cuando no se considera el intercepto en el
(0, 0)
file:///Users/mac/Downloads/M2U2_Exploración_de_la_complejidad_y_el_sobreajuste.html 7/21
7/5/23, 10:02 M2U2_Exploración_de_la_complejidad_y_el_sobreajuste
{'C': 1.0,
Out[ ]:
'class_weight': None,
'dual': False,
'fit_intercept': True,
'intercept_scaling': 1,
'l1_ratio': None,
'max_iter': 100,
'multi_class': 'auto',
'n_jobs': None,
'penalty': 'l2',
'random_state': None,
'solver': 'lbfgs',
'tol': 0.0001,
'verbose': 0,
'warm_start': False}
file:///Users/mac/Downloads/M2U2_Exploración_de_la_complejidad_y_el_sobreajuste.html 8/21
7/5/23, 10:02 M2U2_Exploración_de_la_complejidad_y_el_sobreajuste
weights
# Entrenamos el modelo
model.fit(X_train, y_train)
# Mostramos la región de decisión y los puntos con sus etiquetas.
plot_data(X_train, y_train, model = model, ax=ax[i], title=f"Pesos por clas
fig.tight_layout()
file:///Users/mac/Downloads/M2U2_Exploración_de_la_complejidad_y_el_sobreajuste.html 9/21
7/5/23, 10:02 M2U2_Exploración_de_la_complejidad_y_el_sobreajuste
file:///Users/mac/Downloads/M2U2_Exploración_de_la_complejidad_y_el_sobreajuste.html 10/21
7/5/23, 10:02 M2U2_Exploración_de_la_complejidad_y_el_sobreajuste
file:///Users/mac/Downloads/M2U2_Exploración_de_la_complejidad_y_el_sobreajuste.html 11/21
7/5/23, 10:02 M2U2_Exploración_de_la_complejidad_y_el_sobreajuste
4. Capacidad de un modelo
La capacidad o complejidad de un modelo es su habilidad de ajustarse a una amplia
variedad de funciones.
Una forma de controlar la capacidad de un algoritmo de aprendizaje es elegir su espacio de
hipótesis, el conjunto de funciones que puede seleccionar como la solución.
Por ejemplo, en un modelo de regresión polinomial la capacidad se puede controlar
especificando el máximo grado del polinomio que se puede aprender. A mayor grado
d d
En el lado izquierdo de la gráfica, ambos errores son altos, esta es la zona que corresponde
al subajuste. A medida que aumentamos la capacidad, el error de entrenamiento se reduce,
file:///Users/mac/Downloads/M2U2_Exploración_de_la_complejidad_y_el_sobreajuste.html 12/21
7/5/23, 10:02 M2U2_Exploración_de_la_complejidad_y_el_sobreajuste
5.apropiado.
Subajuste, Sobreajuste y ajuste
Un algoritmo de aprendizaje automático busca cumplir los siguientes objetivos:
Hacer que el error de entrenamiento sea bajo.
Hacer que la brecha entre el error de entrenamiento y el error de prueba sea pequeña.
Dependiendo del desempeño del algoritmo en estas dos habilidades se habla de que el
modelo resultante tiene subajuste, sobreajuste o ajuste apropiado.
6.1 Sobreajuste
file:///Users/mac/Downloads/M2U2_Exploración_de_la_complejidad_y_el_sobreajuste.html 13/21
7/5/23, 10:02 M2U2_Exploración_de_la_complejidad_y_el_sobreajuste
knn = KNeighborsClassifier(n_neighbors=1)
knn.fit(X_train, y_train)
Out[ ]: ▾ KNeighborsClassifier
KNeighborsClassifier(n_neighbors=1)
file:///Users/mac/Downloads/M2U2_Exploración_de_la_complejidad_y_el_sobreajuste.html 14/21
7/5/23, 10:02 M2U2_Exploración_de_la_complejidad_y_el_sobreajuste
6.2 Subajuste
In [ ]: knn = KNeighborsClassifier(n_neighbors=400)
knn.fit(X_train, y_train)
Out[ ]: ▾ KNeighborsClassifier
KNeighborsClassifier(n_neighbors=400)
file:///Users/mac/Downloads/M2U2_Exploración_de_la_complejidad_y_el_sobreajuste.html 16/21
7/5/23, 10:02 M2U2_Exploración_de_la_complejidad_y_el_sobreajuste
Podemos observar que cuando aumentamos el número de vecinos, nuestro modelo sufre de
subajuste. La superficie de decisión se suaviza, pero no logra captar los detalles de los
datos. Tanto el error de entrenamiento como el error de generalización se acercan a . 19%
¿Cómo estimar un buen número de -vecinos más cercanos de manera que el modelo
k
file:///Users/mac/Downloads/M2U2_Exploración_de_la_complejidad_y_el_sobreajuste.html 17/21
7/5/23, 10:02 M2U2_Exploración_de_la_complejidad_y_el_sobreajuste
modelo.
A continuación, exploramos un conjunto de valores , con el objetivo de encontrar aquél
k
file:///Users/mac/Downloads/M2U2_Exploración_de_la_complejidad_y_el_sobreajuste.html 18/21
7/5/23, 10:02 M2U2_Exploración_de_la_complejidad_y_el_sobreajuste
Se observa que el error de entrenamiento es más alto para modelos más simples (valor de k
alto) y tiende a cero para modelos más complejos (valor bajo de ). Además, el error de k
In [ ]: knn = KNeighborsClassifier(n_neighbors=13)
knn.fit(X_train, y_train)
file:///Users/mac/Downloads/M2U2_Exploración_de_la_complejidad_y_el_sobreajuste.html 19/21
7/5/23, 10:02 M2U2_Exploración_de_la_complejidad_y_el_sobreajuste
Recursos adicionales
Los siguientes enlaces corresponden a sitios en donde encontrará información muy útil para
profundizar en el conocimiento de las funcionalidades de la librería Scikit-learn en la
evaluación de la complejidad de sus modelos, además de material de apoyo teórico para
reforzar estos conceptos:
Scikit-learn - Underfitting vs Overfitting
Machine Learning Mastery - Overfitting and Underfitting with machine learning
algorithms
Deep Learning Book - Chapter 5 - Machine Learning Basics
Elite Data Science - Overfitting in Machine Learning
Créditos
Profesor: Fabio Augusto González
Asistentes docentes:
Miguel Angel Ortiz Marín
Alberto Nicolai Romero Martínez
Universidad Nacional de Colombia - Facultad de Ingeniería
file:///Users/mac/Downloads/M2U2_Exploración_de_la_complejidad_y_el_sobreajuste.html 20/21
7/5/23, 10:02 M2U2_Exploración_de_la_complejidad_y_el_sobreajuste
file:///Users/mac/Downloads/M2U2_Exploración_de_la_complejidad_y_el_sobreajuste.html 21/21
7/5/23, 10:12 M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión
1. Dependencias
Importamos las librerías necesarias y definimos algunas funciones básicas de visualización
que vamos a usar en algunos ejemplos.
1.1. Dependencias
Para la construcción de modelos y ejecución de procedimientos metodológicos de
aprendizaje automático, utilizaremos la librería Scikit-learn ( sklearn ) y varias de sus
funciones y conjuntos de datos.
In [ ]: !pip install --upgrade matplotlib mlxtend
file:///Users/mac/Downloads/M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión.html 1/31
7/5/23, 10:12 M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión
Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-w
heels/public/simple/
Requirement already satisfied: matplotlib in /usr/local/lib/python3.9/dist-pac
kages (3.7.1)
Requirement already satisfied: mlxtend in /usr/local/lib/python3.9/dist-packag
es (0.21.0)
Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.9/dis
t-packages (from matplotlib) (23.0)
Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.
9/dist-packages (from matplotlib) (2.8.2)
Requirement already satisfied: pillow>=6.2.0 in /usr/local/lib/python3.9/dist-
packages (from matplotlib) (8.4.0)
Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.9/di
st-packages (from matplotlib) (3.0.9)
Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.9/d
ist-packages (from matplotlib) (4.39.2)
Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.9/di
st-packages (from matplotlib) (1.0.7)
Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.9/dist-p
ackages (from matplotlib) (0.11.0)
Requirement already satisfied: numpy>=1.20 in /usr/local/lib/python3.9/dist-pa
ckages (from matplotlib) (1.22.4)
Requirement already satisfied: importlib-resources>=3.2.0 in /usr/local/lib/py
thon3.9/dist-packages (from matplotlib) (5.12.0)
Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.9/d
ist-packages (from matplotlib) (1.4.4)
Requirement already satisfied: scikit-learn>=1.0.2 in /usr/local/lib/python3.
9/dist-packages (from mlxtend) (1.2.2)
Requirement already satisfied: scipy>=1.2.1 in /usr/local/lib/python3.9/dist-p
ackages (from mlxtend) (1.10.1)
Requirement already satisfied: joblib>=0.13.2 in /usr/local/lib/python3.9/dist
-packages (from mlxtend) (1.1.1)
Requirement already satisfied: pandas>=0.24.2 in /usr/local/lib/python3.9/dist
-packages (from mlxtend) (1.4.4)
Requirement already satisfied: setuptools in /usr/local/lib/python3.9/dist-pac
kages (from mlxtend) (67.6.0)
Requirement already satisfied: zipp>=3.1.0 in /usr/local/lib/python3.9/dist-pa
ckages (from importlib-resources>=3.2.0->matplotlib) (3.15.0)
Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.9/dist-p
ackages (from pandas>=0.24.2->mlxtend) (2022.7.1)
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.9/dist-packa
ges (from python-dateutil>=2.7->matplotlib) (1.16.0)
Requirement already satisfied: threadpoolctl>=2.0.0 in /usr/local/lib/python3.
9/dist-packages (from scikit-learn>=1.0.2->mlxtend) (3.1.0)
# Importamos scikit-learn
import sklearn
file:///Users/mac/Downloads/M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión.html 2/31
7/5/23, 10:12 M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión
Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-w
heels/public/simple/
Requirement already satisfied: scikit-learn in /usr/local/lib/python3.9/dist-p
ackages (1.2.2)
Requirement already satisfied: joblib>=1.1.1 in /usr/local/lib/python3.9/dist-
packages (from scikit-learn) (1.1.1)
Requirement already satisfied: threadpoolctl>=2.0.0 in /usr/local/lib/python3.
9/dist-packages (from scikit-learn) (3.1.0)
Requirement already satisfied: scipy>=1.3.2 in /usr/local/lib/python3.9/dist-p
ackages (from scikit-learn) (1.10.1)
Requirement already satisfied: numpy>=1.17.3 in /usr/local/lib/python3.9/dist-
packages (from scikit-learn) (1.22.4)
Python 3.9.16
Scikit-learn 1.2.2
NumPy 1.22.4
Pandas 1.4.4
Matplotlib 3.7.1
Seaborn 0.12.2
file:///Users/mac/Downloads/M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión.html 3/31
7/5/23, 10:12 M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión
In [ ]: def list_confusion_matrix(cm,classes):
df = pd.DataFrame(data = cm,
index = pd.MultiIndex.from_product([['Valor real'], classes
columns = pd.MultiIndex.from_product([['Valor predicho'], c
return df
2. Conjuntos de datos
Como se mencionó, utilizaremos el conjunto de datos Iris para los ejemplos de clasificación
binaria y clasificación con varias clases y el conjunto de datos Boston para los ejemplos de
regresión.
2.1. Conjunto de datos Iris
Para el problema de clasificación binaria solo consideraremos etiquetas y para 2
clasificación con varias clases usaremos las etiquetas del conjunto de datos Iris.En está
3
iris = datasets.load_iris()
Podemos observar que contiene este objeto que nos regresa Scikit-learn usando el atributo
keys() :
In [ ]: iris.keys()
Con la llave DESCR podemos acceder a una descripción general del conjunto de datos:
In [ ]: print(iris.DESCR)
file:///Users/mac/Downloads/M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión.html 5/31
7/5/23, 10:12 M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión
.. _iris_dataset:
:Summary Statistics:
The famous Iris database, first used by Sir R.A. Fisher. The dataset is taken
from Fisher's paper. Note that it's the same as in R, but not as in the UCI
Machine Learning Repository, which has two wrong data points.
.. topic:: References
Observamos que cada fila corresponde a un ejemplar de una especie de flor. Cada flor tiene
asociado una serie de características, como el ancho y largo del sépalo, y el ancho y largo
del pétalo.
file:///Users/mac/Downloads/M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión.html 7/31
7/5/23, 10:12 M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión
In [ ]: print(iris.target_names)
file:///Users/mac/Downloads/M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión.html 8/31
7/5/23, 10:12 M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión
Podemos observar que en general la clase setosa se encuentra bien separada de las clases
versicolor y virginica.
2.2 Conjunto de datos Boston
Cargamos el conjunto de datos Boston con scikit-learn:
In [ ]: # Loader del conjunto de datos Boston.
from sklearn.datasets import fetch_openml
['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD', 'TAX', 'PTRA
TIO', 'B', 'LSTAT']
Para saber mejor a que se refieren las abreviaciones podemos revisar la descripción del
conjunto de datos con el atributo DESCR :
In [ ]: print(boston['DESCR'])
**Author**:
**Source**: Unknown - Date unknown
**Please cite**:
Podemos ver que el conjunto de datos tiene características como índices de criminalidad,
impuestos, número de cuartos, entre otros, de propiedades en zonas urbanas. La variable
objetivo target corresponde a la variable MEDV , que representa la mediana del valor de
las casas en una zona.
Veamos los primeros ejemplos: 5
Out[ ]: CRIM ZN INDUS CHAS NOX RM AGE DIS RAD TAX PTRATIO B LST
0 0.00632 18.0 2.31 0 0.538 6.575 65.2 4.0900 1 296.0 15.3 396.90 4
1 0.02731 0.0 7.07 0 0.469 6.421 78.9 4.9671 2 242.0 17.8 396.90 9
2 0.02729 0.0 7.07 0 0.469 7.185 61.1 4.9671 2 242.0 17.8 392.83 4
3 0.03237 0.0 2.18 0 0.458 6.998 45.8 6.0622 3 222.0 18.7 394.63 2
4 0.06905 0.0 2.18 0 0.458 7.147 54.2 6.0622 3 222.0 18.7 396.90 5
3.(KNN)
Algoritmo: K-vecinos más cercanos
La clasificación basada en vecinos es un tipo de aprendizaje basado en ejemplos. El modelo
almacena los ejemplos vistos durante entrenamiento y clasifica un elemento no visto
usando una simple regla de votación por mayoría. Si se ubica un punto en el espacio de
características, se le asigna como clase el valor de la clase que tenga la mayor cantidad de
ejemplos en la vecindad del punto. Este ejemplo lo podemos ver ilustrado en la siguiente
imagen:
file:///Users/mac/Downloads/M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión.html 11/31
7/5/23, 10:12 M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión
Para ilustrar el concepto utilizaremos el conjunto de datos artificial de medias lunas moons
de Scikit-learn:
In [ ]: # Generamos un conjunto de datos artificial de dos clases en forma de medias lu
X_moons, y_moons = datasets.make_moons(n_samples=100, noise=0.3, random_state=0
definido por el usuario que determina cuántos vecinos evalúa para determinar la clase de
una instancia nunca antes vista. La elección de este parámetro es definida totalmente por la
naturaleza de los datos.
Vamos a declarar el clasificador y entrenarlo con los datos del conjunto de datos artificial:
In [ ]: from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors= 1)
knn.fit(X_moons, y_moons)
Out[ ]: ▾ KNeighborsClassifier
KNeighborsClassifier(n_neighbors=1)
En este caso definimos que solo tenga en cuenta vecino más cercano. Si visualizamos la
k 1
región de decisión podremos observar unas franjas de color azul (clase A) en la zona
file:///Users/mac/Downloads/M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión.html 12/31
7/5/23, 10:12 M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión
predominantemente naranja (clase B), en las cuales el valor más cercano es un único valor
de la clase A ubicado por aleatoriedad.
In [ ]: plot_decision_region(X_moons, y_moons, knn,
classes = ['A', 'B'],
title = 'KNN como clasificador de medias lunas')
Observaremos que dependiendo del valor de vecinos más cercanos que definamos, k
file:///Users/mac/Downloads/M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión.html 13/31
7/5/23, 10:12 M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión
pertenece). Para realizar un modelo de este tipo con Iris vamos a filtrar aquellas flores que
pertenezcan a las clases versicolor y virginica.
In [ ]: X = iris.data
y = iris.target
In [ ]: X.shape, y.shape
n = 30
print(f'Número de instancias a predecir: {n}')
print(f'Valores reales: {y[:n]}')
print(f'Valores predichos: {predictions[:n]}')
Train Test
X y
1.52 4.5 1.3 0
-0.5 4 3.9 1
Una de las prácticas recomendadas, es particionar los datos para entrenamiento y 70%
30% para prueba. Cuando el número de muestras es muy grande ( ), podemos ≥ 70K
file:///Users/mac/Downloads/M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión.html 15/31
7/5/23, 10:12 M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión
El argumento stratify le indica a Scikit-learn que se desea estratificar los datos con
respecto a y .
Vamos a verificar el número de muestras de ambas particiones y la distribución de clases
de cada una.
In [ ]: print(f'Número de muestras en entrenamiento: {X_train.shape[0]}')
print(f'Número de muestras en prueba: {X_test.shape[0]}')
print(f'Número de características: {X_train.shape[1]}')
classifier = KNeighborsClassifier(n_neighbors=5)
classifier.fit(X_train, y_train)
Out[ ]: ▾ KNeighborsClassifier
KNeighborsClassifier()
0.8666666666666667
Out[ ]:
file:///Users/mac/Downloads/M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión.html 16/31
7/5/23, 10:12 M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión
0.8666666666666667
Out[ ]:
y_pred = classifier.predict(X_test)
accuracy_score(y_test, y_pred)
0.8666666666666667
Out[ ]:
y_pred = classifier.predict(X_test)
cnf_matrix = confusion_matrix(y_test, y_pred)
de confusión nos permite comparar el rendimiento de nuestro clasificador clase por clase.
In [ ]: cnf_matrix
array([[12, 3],
Out[ ]:
[ 1, 14]])
A continuación, vamos a usar la función definida al comienzo de este notebook para generar
de una forma más visual la matriz de confusión.
file:///Users/mac/Downloads/M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión.html 17/31
7/5/23, 10:12 M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión
In [ ]: class_names = iris.target_names[1:]
list_confusion_matrix(cnf_matrix,class_names)
¿Cómo interpretarla?
Los valores en la diagonal indican los aciertos de nuestro clasificador. Por ejemplo,
sabemos que de ejemplos de la clase virginica, supo clasificar , mientras que de
15 14
99
Accuracy = = 99%
100
1
Error = = 1%
100
file:///Users/mac/Downloads/M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión.html 18/31
7/5/23, 10:12 M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión
FP+FN
error =
VP+VN+FP+FN
F1
PRE∗REC
F1 = 2 ∗
PRE+REC
Precision = = No definida
0
Recall
0
0
Recall = = 0%
1
Scikit-learn provee diferentes funciones para calcular estas tres medidas. Estas son:
Precisión: sklearn.metrics.precision_score
Recall: sklearn.metrics.recall_score
F1 score: sklearn.metrics.f1_score
Vamos a medir el desempeño sobre el clasificador : G
Precisión: 0.0
Recall: 0.0
F_1 score: 0.0
Precisión: 0.8235
Recall: 0.9333
F_1 score: 0.8750
5.Multiclase
Evaluación del desempeño - Clasificación
file:///Users/mac/Downloads/M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión.html 20/31
7/5/23, 10:12 M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión
Esta vez usaremos todos los ejemplos de cada una de las tres especies de flor del dataset
Iris. Para obtener una representación gráfica, nos limitaremos a dos variables numéricas de
entrada (longitud del sépalo en y longitud del pétalo en ).
x y
X = iris.data[:,[0, 2]]
y = iris.target
Entrenaremos dos modelos KNN clf_k1 y clf_k1 , donde clf_k5 usará los vecinos
5
Out[ ]: ▾ KNeighborsClassifier
KNeighborsClassifier(n_neighbors=1)
Out[ ]: ▾ KNeighborsClassifier
KNeighborsClassifier()
file:///Users/mac/Downloads/M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión.html 21/31
7/5/23, 10:12 M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión
file:///Users/mac/Downloads/M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión.html 22/31
7/5/23, 10:12 M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión
Podemos notar que a medida que n_neighbors es mayor, la región de decisión es más
suave. En el caso de n_neighbors = 1 , el modelo se está ajustando a las
particularidades de la partición de entrenamiento.
5.1. Matriz de confusión con más de 2 clases
La matriz de confusión se puede extender al problema multiclase de la siguiente manera:
Primero, visualizaremos la matriz de confusión para el modelo KNN con n_neighbors=1 :
In [ ]: y_pred = clf_k1.predict(X_test)
mientras corresponde a los valores predichos por nuestro clasificador para el mismo
y
^
conjunto.
Scikit-Learn nos permite calcular el accuracy de la misma manera que con un modelo de
clasificación binaria:
In [ ]: print(f'Accuracy n_neighbors = 1: {clf_k1.score(X_test, y_test):.4f}')
print(f'Accuracy n_neighbors = 5: {clf_k5.score(X_test, y_test):.4f}')
La métrica de precisión era calculada con base a la matriz de confusión del problema de
clasificación binaria. De igual manera, se puede extender como medida de desempeño para
el problema multiclase de varias formas. Recordemos que:
VP
Precisión =
VP+FP
VP
Recall =
VP+FN
PRE∗REC
F1 = 2 ∗
PRE+REC
Para ilustrar como se calcula cada una de estas medidas, usaremos el clasificador con
n_neighbors=1 .
Primero calculamos la precisión para cada clase y luego determinamos la forma en la que
combinamos las precisiones de cada clase. Scikit-Learn nos permite calcular la precisión y
file:///Users/mac/Downloads/M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión.html 24/31
7/5/23, 10:12 M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión
Añadimos un par de cálculos a nuestra tabla con la matriz de confusión, donde reflejamos la
suma de los valores totales de verdaderos positivos, falsos positivos y falsos negativos.
Existen varias formas de combinar o agregar las medidas de precisión y recall por clase, que
son definidas a partir del argumento average de las métricas mencionadas. Algunos de
los posibles valores son:
micro : Cuenta el total de positivos verdaderos, falsos positivos y falsos negativos
para realizar el cálculo de la métrica.
macro : Calcula la métrica por cada clase y luego la promedia (sin tener en cuenta el
balance de clases).
weighted : Calcula la precisión por clase y luego la promedia teniendo en cuenta el
balance de clases.
Clase VP FP FN PRE REC
Setosa 15 0 0 1.0 1.0
Versicolor 14 3 1 0.824 0.933
Virginica 12 1 3 0.923 0.800
Sum(micro) 41 4 4 0.911 0.911
Avg(macro) 0.916 0.911
In [ ]: print(f"Precisión macro: {precision_score(y_test, y_pred, average='macro'):.4f}
print(f"Precisión micro: {precision_score(y_test, y_pred, average='micro'):.4f}
print(f"Precisión ponderada: {precision_score(y_test, y_pred, average='weighted
file:///Users/mac/Downloads/M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión.html 25/31
7/5/23, 10:12 M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión
Precisión macro: 0.9155
Precisión micro: 0.9111
Precisión ponderada: 0.9155
Como observamos, estos valores corresponden a las dos últimas filas que se calcularon
sobre la tabla de precisión y recall. Vale la pena anotar que weighted y macro son
iguales cuando la clase es balanceada, tal como en el ejemplo de Iris. Esto se puede
extender al cálculo del . Recordemos que el
F1 score es un promedio ponderado de
F1 score
la precisión y el recall.
In [ ]: from sklearn.metrics import f1_score
F1 macro: 0.9107
F1 micro: 0.9111
F1 ponderada: 0.9107
Para finalizar, Scikit-Learn permite realizar un reporte general con todas las métricas
mencionadas con la función classification_report del módulo sklearn.metrics :
In [ ]: from sklearn.metrics import classification_report
print(classification_report(y_test,
y_pred,
target_names=iris.target_names,
digits=4))
accuracy 0.9111 45
macro avg 0.9155 0.9111 0.9107 45
weighted avg 0.9155 0.9111 0.9107 45
En esta sección veremos la evaluación del desempeño para modelos de regresión, usando
el conjunto de datos Boston. Como es usual, primero realizamos una partición de
entrenamiento y prueba tomando el para prueba. 30%
In [ ]: X, y = boston.data, boston.target
X_train, X_test, y_train, y_test = train_test_split(X, y,
random_state=12, test_size=
model = KNeighborsRegressor(n_neighbors=5,
weights='distance')
model.fit(X_train, y_train)
Out[ ]: ▾ KNeighborsRegressor
KNeighborsRegressor(weights='distance')
Si usamos el método score del modelo nos retornará la métrica conocida como el
coeficiente de determinación, y no la exactitud del modelo. En un problema de regresión
no tiene sentido hablar de exactitud u otras métricas cómo la precisión o el recall.
In [ ]: model.score(X_test, y_test)
0.4743034798512158
Out[ ]:
file:///Users/mac/Downloads/M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión.html 27/31
7/5/23, 10:12 M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión
Donde:
y − Etiqueta Real
^ − Predicción
y
El MSE toma la diferencia entre la etiqueta y la predicción (error) por cada ejemplo, las eleva
al cuadrado y las suma y las divide sobre el total de ejemplos. En otras palabras, el MSE es
la media del error al cuadrado . Note que por definición el MSE solo toma valores
(y
^i − y i )
2
mayores o iguales a . 0
Tomar el cuadrado de los errores permite evaluar diferencias positivas tanto negativas de la
misma manera. Tenga en cuenta que esto también implica que el orden de y no es ^
y yi
Tomar el cuadrado también penaliza los errores más grandes. Un MSE pequeño índica que,
en promedio, los errores para todos los ejemplos son pequeños. Otra manera de interpretar
el MSE es como la varianza de los errores (que tan dispersos son). El MSE tiene muchas
interpretaciones estadísticas importantes, como la descomposición en varianza y sesgo, las
cuales no están dentro del alcance de este curso.
En Scikit-learn, el MSE puede ser calculado con el método mean_squared_error de la
siguiente manera:
In [ ]: from sklearn.metrics import mean_squared_error
y_pred = model.predict(X_test)
mean_squared_error(y_test, y_pred)
46.11812861720047
Out[ ]:
n
1
2
RMSE = ∑( y
^ − yi )
i
⎷ n
i=0
Donde:
y − Etiqueta Real
y
^ − Predicción
Aunque sea simplemente la raíz del MSE, el RMSE tiene la ventaja de ser interpretable en las
unidades originales del problema.
EL RMSE puede ser calculado de la siguiente manera:
In [ ]: np.sqrt(mean_squared_error(y_test, y_pred))
6.791032956568571
Out[ ]:
1 n
2
∑ ^ − yi )
(y
n i=0 i
2
R = 1 −
n
1 2
n
∑ (yi − ȳ )
i=0
Donde:
y − Etiqueta Real
y
^ − Predicción
1 n
2
ȳ − Media de y: ∑ y
n i=0 i
file:///Users/mac/Downloads/M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión.html 29/31
7/5/23, 10:12 M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión
Dicho lo anterior, si definimos el MSE del modelo de la media como MMSE (Mean Model
Squared Error) entonces puede ser escrito de la siguiente manera:
R
2
2
MSE MMSE − MSE
R = 1 − =
MMSE MMSE
mucho peores). También cabe notar que el coeficiente de determinación es dependiente del
conjunto de datos, y por lo tanto no es comparable entre distintos conjuntos de datos.
Se dice que el coeficiente representa la proporción de la varianza (de y) que ha sido
explicada por las variables independientes en el modelo. Indica que tan bien serán
predichos ejemplos nunca antes vistos por el modelo, a través de la proporción de esa
varianza explicada.
Como ya se mostró, el coeficiente de determinación puede ser calculado a través de la
función score de los modelos de regresión. Sin embargo, también se puede calcular a
través del método r2_score de sklearn.metrics :
In [ ]: from sklearn.metrics import r2_score
y_pred = model.predict(X_test)
De esta manera podemos determinar que el modelo representa una mejora sobre el modelo
de las medias. Sin embargo, aún puede mejorarse el desempeño.
Recursos adicionales
Los siguientes enlaces corresponden a sitios en donde encontrará información muy útil para
profundizar en el conocimiento de las funcionalidades de la librería Scikit-learn para la
evaluación del desempeño de sus modelos, además de material de apoyo teórico para
reforzar estos conceptos:
scikit-learn - Model Evaluation
mlcourse.ai - Decision Trees and KNN
Metrics to understand regression model in plain english
Difference Between Classification and Regression in Machine Learning
file:///Users/mac/Downloads/M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión.html 30/31
7/5/23, 10:12 M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión
Créditos
Profesor: Fabio Augusto González
Asistentes docentes:
Miguel Angel Ortiz Marín
Alberto Nicolai Romero Martínez
Universidad Nacional de Colombia - Facultad de Ingeniería
file:///Users/mac/Downloads/M2U2_Evaluación_del_Desempeño_de_Clasificación_y_Regresión.html 31/31
7/5/23, 16:00 grupo4
plt.style.use("ggplot")
Carga de Datos
In [ ]: time = np.random.uniform(0, 10, size=(1000, 1))
position = np.exp(-0.2 * time) * np.cos(2 * time) + np.random.normal(0, 0.1, si
In [ ]: fig, ax = plt.subplots()
ax.scatter(time, position, alpha=0.2)
ax.set(xlabel="Tiempo [s]", ylabel="Posicion [cm]")
Preprocesamiento
In [ ]: np.exp(1000)
file:///Users/mac/Downloads/grupo4.html 1/4
7/5/23, 16:00 grupo4
inf
Out[ ]:
In [ ]: np.exp(-0.1)
0.9048374180359595
Out[ ]:
x − min (x)
′
x =
max (x) − min (x)
In [ ]: scaler = MinMaxScaler().fit(time)
time_t = scaler.transform(time)
In [ ]: fig, ax = plt.subplots()
ax.scatter(time_t, position, alpha=0.2)
ax.set(xlabel="Tiempo [s]", ylabel="Posicion [cm]")
In [ ]: time_n = scaler.inverse_transform(time_t)
time_n.min(), time_n.max()
(0.003010875474882546, 9.98506355700189)
Out[ ]:
Validacion Cruzada
In [ ]: time_train, time_test, position_train, position_test = train_test_split(
time_t, position, test_size=0.3, random_state=0
file:///Users/mac/Downloads/grupo4.html 2/4
7/5/23, 16:00 grupo4
)
Modelamiento
In [ ]: model = SVR(gamma=100).fit(time_train, position_train)
/usr/local/lib/python3.9/dist-packages/sklearn/utils/validation.py:1143: DataC
onversionWarning: A column-vector y was passed when a 1d array was expected. P
lease change the shape of y to (n_samples, ), for example using ravel().
y = column_or_1d(y, warn=True)
Evaluacion
In [ ]: model.score(time_train, position_train)
0.9324830029391247
Out[ ]:
In [ ]: model.score(time_test, position_test)
0.9302732695254807
Out[ ]:
In [ ]: fig, ax = plt.subplots()
ax.scatter(time_t, position, alpha=0.2)
ax.plot(x_range, y_pred, color="k")
ax.set(xlabel="Tiempo [s]", ylabel="Posicion [cm]")
file:///Users/mac/Downloads/grupo4.html 3/4
7/5/23, 16:00 grupo4
In [ ]: position_train.mean()
0.008677297702295469
Out[ ]:
In [ ]: y_pred = model.predict(time_test)
np.sqrt(mean_squared_error(position_test, y_pred))
0.09755202307869525
Out[ ]:
file:///Users/mac/Downloads/grupo4.html 4/4
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
1. Dependencias
Importamos las librerías necesarias y definimos algunas funciones básicas de visualización
que vamos a usar en algunos ejemplos.
1.1. Dependencias
Para la construcción de modelos y ejecución de procedimientos metodológicos de
aprendizaje automático, utilizaremos la librería Scikit-learn ( sklearn ) y varias de sus
funciones y conjuntos de datos.
In [ ]: # Actualizamos scikit-learn a la última versión
!pip install -U scikit-learn
# Importamos scikit-learn
import sklearn
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 1/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-w
heels/public/simple/
Requirement already satisfied: scikit-learn in /usr/local/lib/python3.9/dist-p
ackages (1.2.2)
Requirement already satisfied: joblib>=1.1.1 in /usr/local/lib/python3.9/dist-
packages (from scikit-learn) (1.1.1)
Requirement already satisfied: scipy>=1.3.2 in /usr/local/lib/python3.9/dist-p
ackages (from scikit-learn) (1.10.1)
Requirement already satisfied: threadpoolctl>=2.0.0 in /usr/local/lib/python3.
9/dist-packages (from scikit-learn) (3.1.0)
Requirement already satisfied: numpy>=1.17.3 in /usr/local/lib/python3.9/dist-
packages (from scikit-learn) (1.22.4)
Python 3.9.16
Scikit-learn 1.2.2
NumPy 1.22.4
Pandas 1.4.4
Matplotlib 3.7.1
Seaborn 0.12.2
Graphviz 0.20.1
if ax is None:
_, ax = plt.subplots(dpi = 110)
y_unique = np.unique(y)
df = pd.DataFrame({'x1': X[:,0], 'x2': X[:,1], 'Clases': y})
sns.set_theme()
sns.scatterplot(data = df, x = 'x1', y = 'x2',
hue = 'Clases',style = 'Clases', ax = ax, palette = 'Set1')
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 3/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
grid_r, grid_c = XX.shape
ZZ = np.zeros((grid_r, grid_c))
for i in range(grid_r):
for j in range(grid_c):
ZZ[i, j] = pred_fun(XX[i, j], YY[i, j])
balance_point = np.array(generalization_error).argmin() + 1
plt.figure(figsize = (8, 5), dpi = 105)
2. Conjuntos de datos
Para los ejemplos desarrollados en el transcurso de material, se usarán datos de Scikit-
Learn de carácter real (usando Loaders) y sintético (usando Generators).
2.1. Conjunto de datos Iris
En este material retomaremos el conjunto de datos Iris para ilustrar algunos ejemplos. Para
esto, usaremos la función load_iris de Scikit-Learn.
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 4/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
iris = load_iris()
X = iris.data
y = iris.target
Primeras 5 muestras:
[[5.1 3.5 1.4 0.2]
[4.9 3. 1.4 0.2]
[4.7 3.2 1.3 0.2]
[4.6 3.1 1.5 0.2]
[5. 3.6 1.4 0.2]]
Primeras 5 etiquetas:
[0 0 0 0 0]
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 5/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
X, y = make_circles(n_samples=600,
noise=0.1,
random_state=0)
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 6/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
X ~ 600 muestras x 2 características.
y ~ 600 muestras.
Primeras 5 muestras:
[[-0.79959336 0.23505777]
[-0.8693906 0.56906193]
[ 0.03690973 -0.96481524]
[-0.73333376 -0.60035 ]
[-0.27028346 -0.98249038]]
Primeras 5 etiquetas:
[1 0 0 1 0]
make_moons : Este conjunto de datos artificial genera dos variables asociadas a dos
clases que representan dos medias lunas. Scikit-Learn permite a su vez introducir algo
de ruido sobre las muestras creadas.
In [ ]: #Conjunto de datos sintético moons.
from sklearn.datasets import make_moons
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 7/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
Primeras 5 muestras:
[[ 0.77172208 -0.52882117]
[ 0.23023466 0.98205132]
[-0.61846873 0.7614099 ]
[ 1.19039559 -0.66801557]
[-0.34596664 0.73132122]]
Primeras 5 etiquetas:
[1 0 0 1 0]
plot_data(X, y, lr_model)
Score: 0.8883333333333333
Existen problemas en los que generar una clasificación lineal no produce un resultado
apropiado, sin importar el tamaño del conjunto o tiempo invertido en el entrenamiento. Por
lo tanto, surge la necesidad de usar un modelo que permita realizar una clasificación no
lineal.
3. Árboles de Decisión
El primer algoritmo de clasificación no lineal que discutiremos es el basado en árboles de
decisión. Los árboles de decisión son muy intuitivos, pues codifican una serie de
elecciones "si esto" y "si no, entonces", de forma muy similar a como una persona tomaría
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 9/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
una decisión, o un programa simple usando las estructuras if y else . La gran ventaja
de esta técnica es que estas elecciones se pueden aprender de forma automática a partir
de los datos y existen maneras de identificar de manera automática las mejores condiciones
y ramificaciones del árbol generado.
Por ejemplo, considere el siguiente árbol de decisión. Este árbol de decisión describe una
serie de elecciones que buscan determinar si espero (V) o no (F) por una mesa en un
restaurante.
Con base al anterior árbol de decisión, puedo tomar la decisión de esperar o no, usando
unas reglas de clasificación sencillas con preguntas como:
¿Cuántos clientes hay en el restaurante?
¿Cuánto tiempo tengo que esperar?
¿Tengo alguna alternativa de restaurante?
¿Tengo hambre en este momento?
¿Es viernes o sábado?
¿Tengo reservación?
Como puede apreciar, estos árboles pueden tener una interpretación muy intuitiva. Para
tomar una decisión, o más bien realizar una clasificación de la situación, evaluaríamos esta
condición en la observación sobre la que queremos tomar una decisión y avanzamos a la
siguiente condición o estado final. Así, se realizarían preguntas como:
Si Clientes == "Lleno" Y EsperaEstimada == "10-30" Y Hambre ==
"No" Entonces Esperar="SÍ" .
Si Clientes == "Algunos" Entonces Esperar="SI" .
Si Clientes == "Lleno" Y EsperaEstimada == ">60" Entonces
Esperar="NO" .
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 10/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
from IPython.display import HTML
Out[ ]:
classifier = DecisionTreeClassifier()
X_iris = iris.data[:,[0, 2]] # Usamos solo dos variables (longitud del sépalo y
y_iris = iris.target
{'ccp_alpha': 0.0,
Out[ ]:
'class_weight': None,
'criterion': 'gini',
'max_depth': None,
'max_features': None,
'max_leaf_nodes': None,
'min_impurity_decrease': 0.0,
'min_samples_leaf': 1,
'min_samples_split': 2,
'min_weight_fraction_leaf': 0.0,
'random_state': None,
'splitter': 'best'}
moons_DT_classifier = DecisionTreeClassifier()
moons_DT_classifier = moons_DT_classifier.fit(X_moons, y_moons)
Error: 0.0
iris_DT_classifier = DecisionTreeClassifier()
iris_DT_classifier = iris_DT_classifier.fit(X_iris, y_iris)
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 13/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
Error: 0.00666666666666671
Ambos conjuntos de datos tienen un error con valor , que apunta a un posible
0
sobreajuste.
A continuación, vamos a usar el conjunto de datos Iris completo, usando las cuatro
características, y su árbol de decisión, pero esta vez utilizaremos las 4 variables.
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 14/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
Usamos graphviz para visualizar el árbol generado. El método graphviz soporta como
parámetros los nombres de las clases y de las características a graficar. Además, con el
método sklearn.tree.export_graphviz podemos generar la entrada de este método
y así visualizar los modelos que entrenemos.
In [ ]: # Función de utilidad para la visualización de archivos SVG en notebooks.
from IPython.display import SVG
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 15/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
Out[ ]:
Podemos ver como resultó el modelo construido y las reglas que se definieron en la
construcción del árbol. Una cosa a tener en cuenta es la diferenciación inmediata de las
flores de la clase setosa (en naranja) con la primera regla del árbol, en la que para todas
las flores cuyo grosor de pétalo es menor que se clasifican en esta especie.
0.8(cm)
Tras esto, nos podemos imaginar que el grosor de pétalo es especialmente importante para
distinguir las flores setosa. ¿Hay alguna forma de identificar la importancia de cada
variable?
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 16/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
Entonces, podríamos decir que, para el modelo construido, las variables aportan a la
decisión de la siguiente forma:
In [ ]: sns.barplot(x = iris.feature_names, # Nombre de las características.
y = iris_DT_classifier.feature_importances_ ); # Importancia de cad
Para evaluar la complejidad, vamos a estimar este valor tomando como referencia la
profundidad del árbol.
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 17/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 18/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
En este caso, el balance entre ambos errores se alcanza muy rápido, con profundidad de 2
nodos.
Score: 0.502
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 20/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
Para el ejemplo de los dos círculos, podemos llevar los datos a un nuevo espacio más
apropiado. Para esto, usaremos un espacio donde las características corresponden al
cuadrado de las características originales:
2 2
ϕ :R ⟶R
(1)
2 2
(x, y)⟼(x , y )
In [ ]: X_square = X * X
plot_data(X_square, y)
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 21/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
parecidas son dos instancias del conjunto de datos. Formalmente, la función calcula el k
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 22/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
X_iris = iris.data[:,[0, 2]]
y_iris = iris.target
X_train_iris, X_test_iris, y_train_iris, y_test_iris = train_test_split(X_iris,
y_iris,
test_si
random_
T
k(x, y) = ⟨x, y⟩ = xy
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 24/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
Hasta el momento, los resultados son muy similares a los que obtendríamos con otro
método de clasificación lineal.
4.1.2. Kernel Gaussiano
Otro kernel muy importante es el kernel gaussiano. Este está definido por la siguiente
función:
′ 2
∥x − x ∥
′
K(x, x ) = exp(− )
2
2σ
1
γ =
2
2σ
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 25/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
En la literatura este método también se encuentra como kernel usando una función de base
radial (RBF por del ingles Radial basis function).
Para implementar un clasificador de vectores de soporte con un kernel gaussiano podemos
utilizar el constructor de clasificadores basados en máquinas de soporte general
sklearn.SVC . Esta es una versión general de este tipo de clasificador, que acepta
distintos argumentos para definir el método deseado.
En el siguiente ejemplo probamos con un valor pequeño del argumento ( gamma ): γ
rbf_svm.fit(X_train_moons, y_train_moons);
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 26/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
Error en entrenamiento: 0.2000
Error en prueba: 0.2111
La forma ha mejorado, pero ahora tenemos franjas de la clase ocupando el espacio que 0
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 27/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
gamma = 0.7)
rbf_svm.fit(X_train_moons, y_train_moons)
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 28/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
5.modelo
Estimación de los hiperparámetros del
Hasta el momento nos hemos concentrado en evaluar nuestros modelos en una partición de
prueba. Sin embargo, es común introducir sobreajuste a través de la modificación manual
de los hiperparámetros de un modelo conforme vamos reportando el error de
generalización sobre el conjunto de prueba.
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 29/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
Usar la mejor
configuración y entrenar
un modelo sobre la
unión de
"Entrenamiento" y
Reportar el "Validación" Reportar el
Generar n configuraciones
desempeño de cada
para un modelo. Entrenar un
configuración en desempeño
modelo por cada configuración
validación sobre Prueba
Conjunto de datos
En la anterior imagen, introducimos una nueva partición, adicional a la de prueba y
entrenamiento, conocida como partición de "validación". Esta partición es resultado de
tomar la partición de entrenamiento y volver a dividirla (en entrenamiento y validación) de
tal forma que cualquier configuración de parámetros que se use para entrenar un modelo,
pueda ser reportada en validación. Una vez estemos seguros de que tenemos el modelo
con el mejor desempeño en validación, volvemos a unir ambas particiones, entrenamos un
modelo sobre la partición original de entrenamiento y reportamos una sola vez en el
conjunto de prueba.
A pesar de que se introdujo una nueva partición para validar los parámetros de un modelo,
se sigue usando una partición reducida para entrenar el conjunto de datos. La validación
cruzada nos permite usar una mayor parte de los datos para construír el modelo y generar
un estimador más robusto y con mayor capacidad de generalización. En validación cruzada,
los datos son particionados varias veces en entrenamiento y validación de forma repetida.
Finalmente, el desempeño del clasificador es agregado sobre las diferentes particiones de
validación para obtener un estimador más robusto.
La validación cruzada se hace comúnmente de la siguiente manera:
1. Se divide el conjunto de entrenamiento en pliegues o particiones (usualmente 3, 5 o
k
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 30/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
k=1
k=2
k=3
k=4 Entrenamiento
Validación
k=5
classifier_iris = LinearSVC()
scores = cross_val_score(classifier_iris,
X_iris,
y_iris,
cv = 5)
En caso de que se quiera hacer una partición diferente, se puede especificar como
argumento cv otro modelo de validación cruzada. Por ejemplo, si no queremos hacer
partición estratificada podemos usar el constructor sklearn.model_selection.KFold .
Una vez declarado un objeto de tipo KFold , podemos usar el método split para iterar
por los índices de las particiones y para cada pliegue autogenerado.
X y
X = iris.data
y = iris.target
pd.DataFrame(# Conteo de valores por clase. Por los índices de cada pliegue gen
[np.bincount(y[y_index], minlength = 3)
for X_index, y_index in cv_no_stra.split(X, y)]
# Renombramos los índices (pliegues) y columnas (clases).
).rename(index = lambda x: f'Pliegue {x}',
columns = lambda x: f'Clase {x}'
# Creamos una columna para almacenar el accuracy obtenido en cada
).assign(accuracy = cross_val_score(classifier_iris, X_iris, y_ir
Ambos parámetros controlan la complejidad del modelo. Estos parámetros pueden ser
explorados usando un retículo (grid) de valores y evaluando su desempeño usando
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 32/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
Out[ ]:
Definimos los siguientes valores para y C gamma . Vamos a explorar estos valores en el
siguiente rango de potencias de 2:
−5 −4 6 7
2 ,2 ,…,2 ,2
param_grid
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 33/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
Valores de : C
In [ ]: print(param_grid['C'])
Valores de gamma :
In [ ]: print(param_grid['gamma'])
Podemos realizar una validación cruzada con grid search en los hiperparámetros e
identificar la configuración con el mejor score utilizando el método
sklearn.model_selection.GridSearchCV . El objeto retornado por este método
funciona como los demás modelos e implementa funciones como fit , score y
predict .
grid_clf = GridSearchCV(SVC(kernel='rbf'),
param_grid=param_grid,
verbose=1,
return_train_score=True
)
grid_clf.fit(X_train, y_train)
▸ SVC
GridSearchCV nos ofrece una serie de atributos y métodos que nos permiten consultar:
La lista de resultados por elemento en la malla de parámetros( cv_results_ ).
La configuración con el mejor desempeño ( best_params_ ).
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 34/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 35/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
Para encontrar las mejores configuraciones, podemos obtener la tabla de los mayores n
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 36/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
{'C': 1, 'gamma': 1}
0.9619047619047618
Una vez se haya entrenado el modelo usando validación cruzada, GridSearchCV escoge
automáticamente la mejor configuración y vuelve a entrenar un modelo sobre todo el
conjunto de datos de entrenamiento. Por lo tanto tras realizar el entrenamiento con fit se
pueden hacer llamados a funciones como predict() y score() directamente desde el
objeto de grid search.
Para reportar sobre el conjunto de prueba basta con ejecutar:
In [ ]: grid_clf.score(X_test, y_test)
0.9777777777777777
Out[ ]:
(144, 144)
Out[ ]:
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 37/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
Out[ ]: param_gamma 0.03125 0.06250 0.12500 0.25000 0.50000 1.00000 2.00000 4.0000
param_C
0.03125 0.914286 0.923810 0.923810 0.914286 0.923810 0.933333 0.914286 0.8857
0.06250 0.914286 0.923810 0.923810 0.914286 0.923810 0.933333 0.914286 0.8857
0.12500 0.914286 0.923810 0.914286 0.923810 0.933333 0.942857 0.914286 0.8857
0.25000 0.923810 0.914286 0.942857 0.914286 0.942857 0.942857 0.914286 0.91428
0.50000 0.914286 0.942857 0.923810 0.942857 0.952381 0.952381 0.952381 0.9238
1.00000 0.942857 0.933333 0.942857 0.952381 0.942857 0.961905 0.942857 0.91428
2.00000 0.933333 0.952381 0.952381 0.942857 0.961905 0.942857 0.933333 0.90476
4.00000 0.952381 0.952381 0.952381 0.952381 0.942857 0.933333 0.933333 0.90476
8.00000 0.952381 0.961905 0.952381 0.952381 0.942857 0.923810 0.933333 0.89523
16.00000 0.961905 0.952381 0.952381 0.942857 0.914286 0.933333 0.933333 0.89523
32.00000 0.952381 0.952381 0.933333 0.923810 0.914286 0.933333 0.923810 0.89523
64.00000 0.952381 0.942857 0.923810 0.923810 0.923810 0.923810 0.923810 0.89523
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 38/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
Recursos adicionales
Los siguientes enlaces corresponden a sitios en donde encontrará información muy útil para
profundizar en el conocimiento de las funcionalidades de la librería Scikit-learn en la
creación y entrenamiento de modelos de clasificación de lineal, validación cruzada y
búsqueda de hiperparámetros, además de material de apoyo teórico para reforzar estos
conceptos:
mlcourse.ai - Topic 3. Classification, Decision Trees and k Nearest Neighbors
Curso de aprendizaje automático para el INE- Support Vector Machines
A Gentle Introduction to k-fold Cross-Validation
scikit-learn - 3.2.1. Exhaustive Grid Search
Créditos
Profesor: Fabio Augusto Gonzalez
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 39/40
7/5/23, 16:33 M2U3_Métodos_de_clasificación_no_lineal
Asistentes docentes:
Miguel Angel Ortiz Marín
Alberto Nicolai Romero Martínez
Universidad Nacional de Colombia - Facultad de Ingeniería
file:///Users/mac/Downloads/M2U3_Métodos_de_clasificación_no_lineal.html 40/40
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
Análisis de
neuronales series de tiempo con redes
En este material se presentarán las redes neuronales y, en particular, la implementación de
un perceptrón multicapa con Scikit-Learn. Además, y para poner a prueba este tipo de
modelo, se planteará un problema de análisis de series de tiempo, y se entrenará y evaluará
un modelo para este proceso.
1. Dependencias
Importamos las librerías necesarias y definimos algunas funciones básicas de visualización
que vamos a usar en algunos ejemplos.
1.1. Dependencias
Para la construcción de modelos y ejecución de procedimientos metodológicos de
aprendizaje automático, utilizaremos la librería Scikit-learn ( sklearn ) y varias de sus
funciones y conjuntos de datos.
In [ ]: # Actualizamos scikit-learn a la última versión
!pip install -U scikit-learn
# Importamos scikit-learn
import sklearn
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 1/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-w
heels/public/simple/
Requirement already satisfied: scikit-learn in /usr/local/lib/python3.9/dist-p
ackages (1.2.2)
Requirement already satisfied: scipy>=1.3.2 in /usr/local/lib/python3.9/dist-p
ackages (from scikit-learn) (1.10.1)
Requirement already satisfied: joblib>=1.1.1 in /usr/local/lib/python3.9/dist-
packages (from scikit-learn) (1.1.1)
Requirement already satisfied: numpy>=1.17.3 in /usr/local/lib/python3.9/dist-
packages (from scikit-learn) (1.22.4)
Requirement already satisfied: threadpoolctl>=2.0.0 in /usr/local/lib/python3.
9/dist-packages (from scikit-learn) (3.1.0)
Plotly: 4.14.3
In [ ]: # Versión de Python y las demás librerías.
!python --version
print('Scikit-learn', sklearn.__version__)
print('NumPy', np.__version__)
print('Pandas', pd.__version__)
print('Matplotlib', mpl.__version__)
print('Seaborn', sns.__version__)
print('Plotly', plotly.__version__)
Python 3.9.16
Scikit-learn 1.2.2
NumPy 1.22.4
Pandas 1.4.4
Matplotlib 3.7.1
Seaborn 0.12.2
Plotly 5.13.1
if ax is None:
_, ax = plt.subplots(dpi = 110)
y_unique = np.unique(y)
df = pd.DataFrame({'x1': X[:,0], 'x2': X[:,1], 'Clases': y})
sns.set_theme()
sns.scatterplot(data = df, x = 'x1', y = 'x2',
hue = 'Clases',style = 'Clases', ax = ax, palette = 'Set1')
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 3/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
min_x = min_x - (max_x - min_x) * 0.05
max_x = max_x + (max_x - min_x) * 0.05
min_y = min_y - (max_y - min_y) * 0.05
max_y = max_y + (max_y - min_y) * 0.05
ZZ = np.zeros((grid_r, grid_c))
for i in range(grid_r):
for j in range(grid_c):
ZZ[i, j] = pred_fun(XX[i, j], YY[i, j])
train_data = mintemp.loc[:test_date_index[0]]
_y_test, _y_forward, _y_last = ys
# Graficamos los valores predichos.
fig = go.Figure(layout = dict(
title = f'<b>Temperaturas medias semanales (1981-1990)</b> <br> {params}
dragmode= 'pan', width = 1200, height = 600))
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 4/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
fig.add_trace(go.Scatter(x = test_date_index,
y = _y_last,
mode='lines+markers',
name='Valores predichos a partir de datos predichos')
2. Conjuntos de datos
Para los ejemplos desarrollados en el transcurso de material, se usarán datos de Scikit-
Learn de carácter real (usando Loaders) y sintético (usando Generators).
iris = load_iris()
X = iris.data
y = iris.target
Primeras 5 muestras:
[[5.1 3.5 1.4 0.2]
[4.9 3. 1.4 0.2]
[4.7 3.2 1.3 0.2]
[4.6 3.1 1.5 0.2]
[5. 3.6 1.4 0.2]]
Primeras 5 etiquetas:
[0 0 0 0 0]
In [ ]: #Graficamos en un área 2d
plot_data(X, y)
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 5/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
X, y = make_moons(n_samples=600,
noise=0.1,
random_state=0)
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 6/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
X ~ 600 muestras x 2 características.
y ~ 600 muestras.
Primeras 5 muestras:
[[ 0.79376821 -0.51480339]
[ 0.24846934 0.97421613]
[-0.6473948 0.74392718]
[ 1.22860278 -0.596126 ]
[-0.41419323 0.76579368]]
Primeras 5 etiquetas:
[1 0 0 1 0]
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 7/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
url = 'https://drive.google.com/uc?export=download&id=1XvKsdBs6EG463iN3L1lQv9JX
Date
Out[ ]:
1981-01-01 20.700000
1981-01-08 16.585714
1981-01-15 19.214286
1981-01-22 18.514286
1981-01-29 16.814286
Name: Temp, dtype: float64
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 8/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
de la matriz de características X .
Capa(s) ocultas: El número de capas ocultas y el tamaño de cada una es definido por
el parámetro hidden_layer_size de la clase MLPClassifier . Este parámetro
consiste en una tupla de elementos, donde es igual al número de capas ocultas.
n n
x = np.linspace(-5,5, 1000)
logistic = 1 / (1 + np.exp(-x))
relu = np.maximum(0, x)
tanh = np.tanh(x)
identity = x
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 10/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 11/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 12/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 13/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 14/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
clf_iris.fit(X_iris, y_iris)
Out[ ]: ▾ MLPClassifier
MLPClassifier(hidden_layer_sizes=(10, 10), max_iter=1000, solver='sg
d')
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 15/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
0.7
Out[ ]:
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 16/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
Ahora, realizaremos el mismo proceso con los datos del dataset moons.
In [ ]: # Clasificador para el conjunto moons
clf_moons = MLPClassifier(solver='lbfgs', # Método recomendado para datasets pe
activation='tanh', # Función de activación. En este caso
max_iter=1000, # Cantidad máxima de iteraciones perm
tol=1e-4, # Tolerancia de la optimización. Si en una iterac
hidden_layer_sizes=(3, 3)) # Número de neuronas por cada ca
1.0
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 17/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
w0 . El atributo coefs_ nos regresa una lista que corresponde a los parámetros
aprendidos. A continuación, verificamos el tamaño de cada matriz y su respectivo valor:
In [ ]: print([a.shape for a in clf_moons.coefs_])
for coefs_row in clf_moons.coefs_:
print(coefs_row)
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 18/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
[(3,), (3,), (1,)]
[ -0.23458911 -21.5308216 -3.18927969]
[-6.18924982 -8.63073332 2.98571116]
[-21.67943143]
Recomendaciones prácticas
Hacer un escalamiento de los datos de entrada. MLPClassifier es muy sensible a la
escala de los datos de entrada.
Explorar el número de neuronas por capa y el parámetro usando GridSearchCV . α
Usar lbfgs como solver para conjuntos de datos pequeños. Mientras que adam es
más recomendado para conjuntos de datos grandes.
Las series de tiempo son una secuencia de observaciones indexadas por una variable
temporal. Una de las aplicaciones más comunes del análisis de series de tiempo es la
predicción de valores futuros utilizando datos históricos. Por ejemplo, se desea predecir el
valor de la medida en el siguiente minuto, día, mes o año basados en los datos recolectados
en los minutos, días, meses y/o años previos.
datos de entrada o predictores y el valor actual como el valor objetivo o valor explicado. El
ancho de la ventana normalmente se explora como un hiperparámetro.
w
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 20/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
4.2. Series
artificiales de tiempo con redes neuronales
Ahora realizaremos la predicción para el dataset de temperaturas mínimas medias
semanales. Carguemos nuevamente el objeto Series.
In [ ]: # Objeto Series con el conjunto de datos.
url = 'https://drive.google.com/uc?export=download&id=1XvKsdBs6EG463iN3L1lQv9JX
Date
Out[ ]:
1981-01-01 20.700000
1981-01-08 16.585714
1981-01-15 19.214286
1981-01-22 18.514286
1981-01-29 16.814286
Name: Temp, dtype: float64
count 523.000000
Out[ ]:
mean 11.197683
std 3.430824
min 2.742857
25% 8.700000
50% 11.057143
75% 13.821429
max 20.700000
Name: Temp, dtype: float64
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 21/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
Vamos a visualizar la serie de los valores de temperatura. Este será el valor que
predeciremos.
In [ ]: mintemp.plot(rot=90, figsize = (12, 5), fontsize = 13.5);
La red neuronal debe tener entradas o features y salida, que corresponde al valor
k 1
actual. Las features serán las observaciones previas, que corresponden a una ventana de
k
tamaño . k
for i, ax in enumerate(axes.flat):
data = mintemp.iloc[i: i + k]
ax.set_title(f'Ventana {i + 1}')
ax.plot(data.index[:-1], data.values[:-1], 'r')
ax.plot(data.index[-1], data.values[-1], 'go', ms = 12)
ax.plot(data.index[:-1], data.values[:-1], 'ro')
ax.plot(data.index[-2:], data.values[-2:], 'g--')
fig.autofmt_xdate()
fig.tight_layout()
fig.legend(['Ventana', 'Valor']);
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 22/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 23/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
Para generar nuestro modelo vamos a iniciar con una ventana de tiempo de 20
observaciones.
In [ ]: # Tamaño de la ventana. Puede cambiarlo si lo desea.
# Tenga en cuenta que el entrenamiento para valores mayores tardará más tiempo.
k = 20
Usaremos los registros de los primeros años del dataset (desde hasta
7 1981 1986 ) para el
conjunto de entrenamiento y validación y los siguientes (desde hasta 2 1987 1990 ) para el
conjunto de pruebas. Empezamos almacenándolos en arreglos de NumPy.
In [ ]: data_train = mintemp.loc[:'1986-12-31'] # Primeros 7 años
data_test = mintemp.loc['1987-01-01':] # Últimos 3 años.
n = ts.shape[0] - window_size
X = np.empty((n, window_size))
y = np.empty(n)
return X, y
celda podemos ver el arreglo en formato de DataFrame. Note que cada fila es la fila anterior
corrida un movimiento hacia la izquierda.
In [ ]: # Observaciones de X en formato de DataFrame.
pd.DataFrame(X_train)
Out[ ]: 0 1 2 3 4 5 6 7
0 20.700000 16.585714 19.214286 18.514286 16.814286 17.571429 16.585714 19.242857
1 16.585714 19.214286 18.514286 16.814286 17.571429 16.585714 19.242857 16.142857
2 19.214286 18.514286 16.814286 17.571429 16.585714 19.242857 16.142857 17.342857
3 18.514286 16.814286 17.571429 16.585714 19.242857 16.142857 17.342857 13.828571
4 16.814286 17.571429 16.585714 19.242857 16.142857 17.342857 13.828571 12.528571
... ... ... ... ... ... ... ... ...
288 6.842857 6.300000 8.928571 5.814286 9.057143 3.171429 8.242857 8.928571
289 6.300000 8.928571 5.814286 9.057143 3.171429 8.242857 8.928571 8.928571
290 8.928571 5.814286 9.057143 3.171429 8.242857 8.928571 8.928571 8.557143
291 5.814286 9.057143 3.171429 8.242857 8.928571 8.928571 8.557143 9.157143
292 9.057143 3.171429 8.242857 8.928571 8.928571 8.557143 9.157143 8.871429
293 rows × 20 columns
En está el elemento que iría justo después del último valor de la ventana . Note que el
yi Xi
elemento es el último valor de la fila , pues en esa ventana pasa a ser el último
yi Xi+1
0 6.300000
Out[ ]:
1 10.514286
2 11.314286
3 5.728571
4 7.400000
...
288 10.942857
289 12.957143
290 13.871429
291 11.414286
292 11.285714
Length: 293, dtype: float64
TimeSeriesSplit de Scikit-Learn.
In [ ]: # Selección de los datos en series de tiempo
from sklearn.model_selection import TimeSeriesSplit
print("\tPartición de validación")
print(f'\t\tTamaño de la partición: {test_index.shape}')
print(f'\t\tRango de valores: {test_index[0]}-{test_index[-1]}\n')
Partición de validación
Tamaño de la partición: (73,)
Rango de valores: 74-146
Partición de validación
Tamaño de la partición: (73,)
Rango de valores: 147-219
Partición de validación
Tamaño de la partición: (73,)
Rango de valores: 220-292
i = 0
fig = plt.figure(figsize = (12,6), dpi = 110)
plt.set_cmap('Paired')
plt.plot(test_index,
np.full(len(test_index), 1-i*0.001),
lw = 8,
ls= '-',
label = f'Validación (k = {i + 1})')
i+=1
fig.get_axes()[0].get_yaxis().set_visible(False)
plt.legend(ncol=1, title = 'Índices por partición', );
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 27/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
4.3. Regresión
multicapa de series de tiempo con perceptrón
Ahora realizamos la regresión con una red neuronal multicapa, para predecir el valor de la
serie. En esta ocasión utilizaremos MPLRegressor . Sus parámetros son equivalentes a los
aceptados por MLPClassifier , a diferencia que el regresor permite retornar los valores
continuos generados por la función de predicción.
In [ ]: from sklearn.neural_network import MLPRegressor
In [ ]: # Entrenamos el modelo.
model.fit(X_train, y_train)
Out[ ]: ▾ MLPRegressor
MLPRegressor(hidden_layer_sizes=(120, 60, 30), n_iter_no_change=50,
random_state=1234, solver='lbfgs', validation_fraction=0.
2)
In [ ]: # Métricas de rendimiento
# Error absoluto, cuadrado, y cuadrado logarítmico.
from sklearn.metrics import mean_absolute_error, mean_squared_error, mean_squar
y_pred = model.predict(X_test)
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 28/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
print(f"Test Mean Absolute Error: \t{mean_absolute_error(y_test, y_pred):.4f}")
print(f"Test Mean squared log error: \t{mean_squared_log_error(y_test, y_pred):
In [ ]: x = data_test.index[k:]
El objeto generado por TimeSeriesSplit puede ser usado para generar las particiones
de validación cruzada con el método GridSearchCV , pasándolo con el argumento cv .
Nota: La búsqueda explora configuraciones distintas en cada uno de los
12 5
tsp = TimeSeriesSplit(n_splits = 5)
gsearch.fit(X_train, y_train)
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 30/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
Fitting 5 folds for each of 12 candidates, totalling 60 fits
[CV 1/5] END activation=logistic, hidden_layer_sizes=(10,);, score=0.528 total
time= 0.7s
[CV 2/5] END activation=logistic, hidden_layer_sizes=(10,);, score=-0.316 tota
l time= 1.0s
[CV 3/5] END activation=logistic, hidden_layer_sizes=(10,);, score=-0.049 tota
l time= 1.1s
[CV 4/5] END activation=logistic, hidden_layer_sizes=(10,);, score=0.451 total
time= 1.2s
[CV 5/5] END activation=logistic, hidden_layer_sizes=(10,);, score=0.422 total
time= 0.8s
[CV 1/5] END activation=logistic, hidden_layer_sizes=(20,);, score=0.529 total
time= 0.4s
[CV 2/5] END activation=logistic, hidden_layer_sizes=(20,);, score=-0.110 tota
l time= 0.8s
[CV 3/5] END activation=logistic, hidden_layer_sizes=(20,);, score=0.244 total
time= 0.8s
[CV 4/5] END activation=logistic, hidden_layer_sizes=(20,);, score=0.164 total
time= 0.9s
[CV 5/5] END activation=logistic, hidden_layer_sizes=(20,);, score=0.333 total
time= 0.9s
[CV 1/5] END activation=logistic, hidden_layer_sizes=(40,);, score=0.387 total
time= 0.2s
[CV 2/5] END activation=logistic, hidden_layer_sizes=(40,);, score=0.114 total
time= 1.0s
[CV 3/5] END activation=logistic, hidden_layer_sizes=(40,);, score=0.260 total
time= 1.1s
[CV 4/5] END activation=logistic, hidden_layer_sizes=(40,);, score=0.132 total
time= 1.2s
[CV 5/5] END activation=logistic, hidden_layer_sizes=(40,);, score=0.262 total
time= 2.7s
[CV 1/5] END activation=logistic, hidden_layer_sizes=(80,);, score=0.265 total
time= 0.5s
[CV 2/5] END activation=logistic, hidden_layer_sizes=(80,);, score=0.194 total
time= 0.7s
[CV 3/5] END activation=logistic, hidden_layer_sizes=(80,);, score=0.224 total
time= 1.8s
[CV 4/5] END activation=logistic, hidden_layer_sizes=(80,);, score=0.431 total
time= 1.1s
[CV 5/5] END activation=logistic, hidden_layer_sizes=(80,);, score=0.008 total
time= 1.8s
[CV 1/5] END activation=tanh, hidden_layer_sizes=(10,);, score=-0.052 total ti
me= 0.7s
[CV 2/5] END activation=tanh, hidden_layer_sizes=(10,);, score=-0.414 total ti
me= 0.7s
[CV 3/5] END activation=tanh, hidden_layer_sizes=(10,);, score=0.564 total tim
e= 0.8s
[CV 4/5] END activation=tanh, hidden_layer_sizes=(10,);, score=0.677 total tim
e= 0.9s
[CV 5/5] END activation=tanh, hidden_layer_sizes=(10,);, score=0.596 total tim
e= 0.9s
[CV 1/5] END activation=tanh, hidden_layer_sizes=(20,);, score=0.550 total tim
e= 0.7s
[CV 2/5] END activation=tanh, hidden_layer_sizes=(20,);, score=0.069 total tim
e= 0.9s
[CV 3/5] END activation=tanh, hidden_layer_sizes=(20,);, score=0.488 total tim
e= 1.0s
[CV 4/5] END activation=tanh, hidden_layer_sizes=(20,);, score=0.663 total tim
e= 1.6s
[CV 5/5] END activation=tanh, hidden_layer_sizes=(20,);, score=0.372 total tim
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 31/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
e= 1.6s
[CV 1/5] END activation=tanh, hidden_layer_sizes=(40,);, score=0.507 total tim
e= 1.0s
[CV 2/5] END activation=tanh, hidden_layer_sizes=(40,);, score=0.223 total tim
e= 1.2s
[CV 3/5] END activation=tanh, hidden_layer_sizes=(40,);, score=0.050 total tim
e= 1.3s
[CV 4/5] END activation=tanh, hidden_layer_sizes=(40,);, score=0.331 total tim
e= 1.6s
[CV 5/5] END activation=tanh, hidden_layer_sizes=(40,);, score=0.053 total tim
e= 2.8s
[CV 1/5] END activation=tanh, hidden_layer_sizes=(80,);, score=0.419 total tim
e= 0.6s
[CV 2/5] END activation=tanh, hidden_layer_sizes=(80,);, score=0.368 total tim
e= 1.1s
[CV 3/5] END activation=tanh, hidden_layer_sizes=(80,);, score=0.229 total tim
e= 5.1s
[CV 4/5] END activation=tanh, hidden_layer_sizes=(80,);, score=0.244 total tim
e= 4.0s
[CV 5/5] END activation=tanh, hidden_layer_sizes=(80,);, score=0.412 total tim
e= 3.5s
[CV 1/5] END activation=relu, hidden_layer_sizes=(10,);, score=0.540 total tim
e= 0.4s
[CV 2/5] END activation=relu, hidden_layer_sizes=(10,);, score=0.547 total tim
e= 0.2s
[CV 3/5] END activation=relu, hidden_layer_sizes=(10,);, score=0.498 total tim
e= 0.5s
[CV 4/5] END activation=relu, hidden_layer_sizes=(10,);, score=0.518 total tim
e= 0.6s
[CV 5/5] END activation=relu, hidden_layer_sizes=(10,);, score=0.655 total tim
e= 0.5s
[CV 1/5] END activation=relu, hidden_layer_sizes=(20,);, score=-0.223 total ti
me= 0.9s
[CV 2/5] END activation=relu, hidden_layer_sizes=(20,);, score=0.192 total tim
e= 1.0s
[CV 3/5] END activation=relu, hidden_layer_sizes=(20,);, score=0.394 total tim
e= 0.6s
[CV 4/5] END activation=relu, hidden_layer_sizes=(20,);, score=0.541 total tim
e= 0.6s
[CV 5/5] END activation=relu, hidden_layer_sizes=(20,);, score=0.671 total tim
e= 0.5s
[CV 1/5] END activation=relu, hidden_layer_sizes=(40,);, score=0.397 total tim
e= 0.3s
[CV 2/5] END activation=relu, hidden_layer_sizes=(40,);, score=0.236 total tim
e= 0.8s
[CV 3/5] END activation=relu, hidden_layer_sizes=(40,);, score=0.055 total tim
e= 0.5s
[CV 4/5] END activation=relu, hidden_layer_sizes=(40,);, score=0.418 total tim
e= 1.0s
[CV 5/5] END activation=relu, hidden_layer_sizes=(40,);, score=0.337 total tim
e= 1.9s
[CV 1/5] END activation=relu, hidden_layer_sizes=(80,);, score=0.263 total tim
e= 0.4s
[CV 2/5] END activation=relu, hidden_layer_sizes=(80,);, score=0.271 total tim
e= 0.7s
[CV 3/5] END activation=relu, hidden_layer_sizes=(80,);, score=0.213 total tim
e= 2.3s
[CV 4/5] END activation=relu, hidden_layer_sizes=(80,);, score=0.142 total tim
e= 4.3s
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 32/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
[CV 5/5] END activation=relu, hidden_layer_sizes=(80,);, score=0.035 total tim
e= 2.7s
Out[ ]: ▸ GridSearchCV
▸ estimator: MLPRegressor
▸ MLPRegressor
A continuación, vamos a realizar este proceso desde la primera ventana del conjunto de
evaluación, y comparar los resultados con los valores obtenidos al predecir a partir de las
ventanas de evaluación y con los datos reales.
Las líneas generadas en la visualización tienen el siguiente significado:
Valores de entrenamiento y pruebas: La primera ventana de tiempo (en azul)
corresponde a los datos que fueron usados para entrenar y validar el desempeño del
modelo. A partir de su último valor se realizan las predicciones correspondientes.
Valores reales: Esta línea (en rojo) corresponde a los valores reales de la ventana de
tiempo final en el conjunto de datos original. Se visualiza para realizar una comparación
gráfica con los valores predichos por el modelo.
Valores predichos a partir de datos reales: Esta línea (en verde) corresponde a los
valores predichos por el modelo a partir de la ventana previa de valores reales, aunque
su final no coincida con el valor predicho con la ventana inmediatamente anterior.
Valores predichos a partir de datos predichos: Esta línea (en azul) corresponde a los
valores predichos por el modelo a partir de la ventana previa de valores construida a
partir de predicciones continuas. Al inicio se realiza una predicción con los valores
reales del final de la primera ventana de tiempo y se concatena el valor predicho al final
de la nueva ventana usada para predecir. Gracias a esta configuración se podría realizar
teóricamente una lista de predicciones sin límite.
In [ ]: #@markdown **Visualización:** Visualización de los resultados de la regresión a
#@markdown > **Nota**: La función es generada con la librería de visualización
# Últimos valores de entrenamiento a usar para la predicción.
X_last = X_test[:1]
for i in range(len(X_test)):
# Valores predichos a partir de datos reales (X_test)
y_pred_forward = gsearch.predict(X_test[i: i + 1])
y_forward.append(y_pred_forward[0])
test_date_index = data_test.index[k:]
plot_prediction(gsearch.best_params_,
(y_test, y_forward, y_last),
test_date_index)
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 34/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
Podemos utilizar métricas para evaluar el rendimiento obtenido con los dos métodos. El
segundo método, aun usando datos predichos únicamente, produce un resultado bastante
bueno con relación a la poca información real de la que parte para su construcción.
In [ ]: # Datos predichos a partir de datos predichos.
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 35/36
7/5/23, 19:19 M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales
Test Mean Squared Error: 3.2890
Test Mean Absolute Error: 1.4498
Test Mean squared log error: 0.0270
Recursos adicionales
Los siguientes enlaces corresponden a sitios en donde encontrará información muy útil para
profundizar en el conocimiento de las funcionalidades de la librería Scikit-learn en la
creación y entrenamiento de redes neuronales multicapa y el análisis y modelado de
problemas de series de tiempo, además de material de apoyo teórico para reforzar estos
conceptos:
Time Series Machine Learning Regression Framework
How (not) to use Machine Learning for time series forecasting: Avoiding the pitfalls
Analytics Vidhya - Time Series Forecasting using Python
3Blue1Brown - Neural Networks (Lista de reproducción de YouTube)
Fernando Sancho Caparrini - Redes Neuronales: una visión superficial.
Knut Hinkelmann - Neural Networks
MIT Press book - Deep learning book
course.fast.ai
Créditos
Profesor: Fabio Augusto Gonzalez
Asistentes docentes:
Miguel Angel Ortiz Marín
Alberto Nicolai Romero Martínez
Universidad Nacional de Colombia - Facultad de Ingeniería
file:///Users/mac/Downloads/M2U3_Análisis_de_series_de_tiempo_con_redes_neuronales.html 36/36
7/5/23, 19:21 grupo4.ipynb - Colaboratory
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.svm import SVR
from sklearn.model_selection import GridSearchCV, TimeSeriesSplit
from ipywidgets import interact, IntSlider
Carga de Datos
fig, ax = plt.subplots()
ax.plot(time, position)
ax.set(xlabel="Time[s]", ylabel="Position")
ax.grid(True)
fig, ax = plt.subplots()
ax.plot(position)
ax.set(xlabel="Time [samples]", ylabel="Position")
ax.grid(True)
https://colab.research.google.com/drive/1ArmhPT72YC4qtgLxRIzwF1qPfSFzIniN#scrollTo=--TYGktTFiGP&printMode=true 1/13
7/5/23, 19:21 grupo4.ipynb - Colaboratory
Validacion Cruzada
p = 0.6
n_train = int(position.size * p)
position_train, position_test = position[:n_train], position[n_train:]
fig, ax = plt.subplots()
ax.plot(position_train, label="Train")
ax.plot(np.arange(n_train, position.size), position_test, label="Test")
ax.set(xlabel="Time [samples]", ylabel="Position")
ax.grid(True)
ax.legend()
https://colab.research.google.com/drive/1ArmhPT72YC4qtgLxRIzwF1qPfSFzIniN#scrollTo=--TYGktTFiGP&printMode=true 2/13
7/5/23, 19:21 grupo4.ipynb - Colaboratory
<matplotlib.legend.Legend at 0x7f66b4b28700>
Modelamiento
position_train.shape
(6000,)
window = 200
def show_window(x_0):
fig, ax = plt.subplots()
ax.plot(position_train, label="Train", alpha=0.3)
ax.plot(np.arange(n_train, position.size), position_test, label="Test", alpha=0.3)
window_idx = np.arange(x_0, x_0 + window)
position_window = position[window_idx]
ax.plot(window_idx, position_window, color="r", label="Window", alpha=0.3)
ax.scatter(x_0 + window, position[x_0 + window], color="k", s=30)
ax.set(xlabel="Time [samples]", ylabel="Position")
ax.grid(True)
ax.legend()
show_window(0)
https://colab.research.google.com/drive/1ArmhPT72YC4qtgLxRIzwF1qPfSFzIniN#scrollTo=--TYGktTFiGP&printMode=true 3/13
7/5/23, 19:21 grupo4.ipynb - Colaboratory
x_0 0
<function __main__.show_window(x_0)>
https://colab.research.google.com/drive/1ArmhPT72YC4qtgLxRIzwF1qPfSFzIniN#scrollTo=--TYGktTFiGP&printMode=true 4/13
7/5/23, 19:21 grupo4.ipynb - Colaboratory
features_train.shape
(5799, 200)
labels_train.shape
(5799,)
features_test.shape
(3799, 200)
labels_test.shape
(3799,)
model.gamma, model.C
('scale', 1.0)
model.score(features_test, labels_test)
0.9192701276983957
param_grid = {
"gamma": np.logspace(-5, -1, 5),
"C": np.logspace(-2, 2, 5),
}
param_grid
gs = GridSearchCV(
SVR(max_iter=1000),
param_grid=param_grid,
cv=TimeSeriesSplit(n_splits=3)
).fit(features_train, labels_train)
https://colab.research.google.com/drive/1ArmhPT72YC4qtgLxRIzwF1qPfSFzIniN#scrollTo=--TYGktTFiGP&printMode=true 5/13
7/5/23, 19:21 grupo4.ipynb - Colaboratory
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
/usr/local/lib/python3.9/dist-packages/sklearn/svm/_base.py:299: ConvergenceWarni
warnings.warn(
pd.DataFrame(gs.cv_results_)
https://colab.research.google.com/drive/1ArmhPT72YC4qtgLxRIzwF1qPfSFzIniN#scrollTo=--TYGktTFiGP&printMode=true 6/13
7/5/23, 19:21 grupo4.ipynb - Colaboratory
https://colab.research.google.com/drive/1ArmhPT72YC4qtgLxRIzwF1qPfSFzIniN#scrollTo=--TYGktTFiGP&printMode=true 7/13
7/5/23, 19:21 grupo4.ipynb - Colaboratory
gs.best_estimator_
13 0.847147 0.496754 0.713353 0.364175 1.0
▾ SVR
SVR(C=10.0,
14 gamma=0.0001,
0.772444 max_iter=1000) 0.700583
0.642939 0.289745 1.0
best_model = gs.best_estimator_
15 0.751132 0.472385 0.656458 0.242072 10.0 0.0
best_model.score(features_test, labels_test)
0.9098405847335298
16 0.564320 0.316860 0.503374 0.153626 10.0 0
y_pred = best_model.predict(features_test)
17 = plt.subplots()
fig, ax 0.510718 0.277985 0.448051 0.114756 10.0
ax.plot(labels_test, label="test")
ax.plot(y_pred, label="pred")
ax.legend()
18 0.345860 0.178115 0.301454 0.054241 10.0
<matplotlib.legend.Legend at 0x7f66b4b57130>
window = features_train[-1:]
window
https://colab.research.google.com/drive/1ArmhPT72YC4qtgLxRIzwF1qPfSFzIniN#scrollTo=--TYGktTFiGP&printMode=true 8/13
7/5/23, 19:21 grupo4.ipynb - Colaboratory
fig, ax = plt.subplots()
ax.plot(position_test, label="test")
ax.plot(y_pred, label="pred")
ax.legend()
https://colab.research.google.com/drive/1ArmhPT72YC4qtgLxRIzwF1qPfSFzIniN#scrollTo=--TYGktTFiGP&printMode=true 10/13
7/5/23, 19:21 grupo4.ipynb - Colaboratory
<matplotlib.legend.Legend at 0x7f66b4d62f10>
fig, ax = plt.subplots()
ax.plot(y_pred, label="pred")
ax.legend()
<matplotlib.legend.Legend at 0x7f66b4f08a00>
https://colab.research.google.com/drive/1ArmhPT72YC4qtgLxRIzwF1qPfSFzIniN#scrollTo=--TYGktTFiGP&printMode=true 11/13
7/5/23, 19:21 grupo4.ipynb - Colaboratory
https://colab.research.google.com/drive/1ArmhPT72YC4qtgLxRIzwF1qPfSFzIniN#scrollTo=--TYGktTFiGP&printMode=true 13/13
11/5/23, 15:10 M2U4_Aprendizaje_no_supervisado__agrupamiento
1. Dependencias
Importamos las librerías necesarias y definimos algunas funciones básicas de visualización
que vamos a usar en algunos ejemplos.
1.1. Dependencias
Para la construcción de modelos y ejecución de procedimientos metodológicos de
aprendizaje automático, utilizaremos la librería Scikit-learn ( sklearn ) y varias de sus
file:///Users/mac/Downloads/M2U4_Aprendizaje_no_supervisado__agrupamiento (1).html 1/73
11/5/23, 15:10 M2U4_Aprendizaje_no_supervisado__agrupamiento
# Importamos scikit-learn
import sklearn
cm = 'tab10'
fig, ax = plt.subplots(figsize=(8, 6))
plot_cluster_predictions(clustering, X, n_clusters, cm,
plot_data, plot_centers, show_metric, ax = ax
cm = 'tab10'
fig, ax = plt.subplots(figsize=(8, 6))
plot_cluster_predictions(AgglomerativeClustering(connectivity=knn_gra
n_clusters=2, show_metric='silueta', ax = ax)
y = clustering.fit_predict(X)
# remove elements tagged as noise (cluster nb<0)
X = X[y>=0]
y = y[y>=0]
if n_clusters is None:
n_clusters = len(np.unique(y))
if ax is None:
ax = plt.gca()
if plot_data:
sns.scatterplot(x=X[:,0], y=X[:,1], hue=y, palette=cmap,
legend=False, alpha=.5, ax=ax, s=40)
plt.axis("off")
return
2. Conjuntos de datos
Para los ejemplos desarrollados en el transcurso de material, se usarán datos de Scikit-
Learn de carácter real (usando Loaders) y sintético (usando Generators).
Usaremos el dataset Iris para mostrar un ejemplo de evaluación externa, el dataset Titanic
para mostrar un ejemplo de aplicación y finalmente usaremos un conjunto de datos artificial
que cargaremos desde una URL remota.
Cargamos Iris usando el módulo sklearn.datasets .
In [ ]: from sklearn.datasets import load_iris
iris = load_iris()
print(iris.DESCR)
:Summary Statistics:
The famous Iris database, first used by Sir R.A. Fisher. The dataset is taken
from Fisher's paper. Note that it's the same as in R, but not as in the UCI
Machine Learning Repository, which has two wrong data points.
.. topic:: References
Cargamos el dataset Titanic desde una Google drive remoto con gdown:
In [ ]: # Id remoto del conjunto de datos Titanic.
!gdown --id 19ciOuzzyxN-Ht03lBwHAqEyrsmWBUhDK
titanic_df = pd.read_csv('titanic.csv')
titanic_df
Out[ ]: PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare
Braund,
0 1 0 3 Mr. Owen male 22.0 1 0 A/5 21171 7.2500
Harris
Cumings,
Mrs. John
1 2 1 1 Bradley female 38.0 1 0 PC 17599 71.2833
(Florence
Briggs
Th...
Heikkinen,
2 3 1 3 Miss. female 26.0 0 0 STON/O2.
3101282 7.9250
Laina
Futrelle,
Mrs.
3 4 1 1 Jacques female 35.0 1 0 113803 53.1000
Heath
(Lily May
Peel)
Allen, Mr.
4 5 0 3 William male 35.0 0 0 373450 8.0500
Henry
... ... ... ... ... ... ... ... ... ... ...
Montvila,
886 887 0 2 Rev. male 27.0 0 0 211536 13.0000
Juozas
Graham,
887 888 1 1 Miss. female 19.0 0 0 112053 30.0000
Margaret
Edith
Johnston,
Miss. W./C. 23.4500
888 889 0 3 Catherine female NaN 1 2 6607
Helen
"Carrie"
Behr, Mr.
889 890 1 1 Karl male 26.0 0 0 111369 30.0000
Howell
Dooley,
890 891 0 3 Mr. male 32.0 0 0 370376 7.7500
Patrick
891 rows × 12 columns
Retomaremos los conjuntos de datos de medias lunas y de blobs de Scikit-Learn:
In [ ]: from sklearn.datasets import make_blobs, make_moons
X_cluster.shape
(500, 2)
Out[ ]:
plt.scatter(X_cluster[:,0],
X_cluster[:,1]);
Algoritmo:
1. Se seleccionan k centroides aleatoriamente.
2. Se repite hasta que los k centroides no cambien:
3. Se establecen k clusters asignando cada dato al
centroide más cercano.
4. Se recalcula el centroide de cada cluster como el
promedio (mean) de los datos.
En los siguientes videos podrá ver de manera gráfica el concepto del algoritmo aplicado:
In [ ]: #@markdown **Animación: Algoritmo *K-means***
Out[ ]:
Out[ ]:
K-Means Clustering Example
km = KMeans(n_clusters = n)
km.fit(X_cluster)
y = km.predict(X_cluster)
1 392
Out[ ]:
0 108
dtype: int64
In [ ]: km.cluster_centers_
El siguiente código dibuja los datos agrupados junto con los centroides:
In [ ]: plt.figure(dpi = 110)
sns.scatterplot(x = X_cluster[:,0], y = X_cluster[:,1], hue = y)
plt.scatter(km.cluster_centers_[:,0], km.cluster_centers_[:,1],
marker="x", lw=3, s=200, color = 'k')
{'algorithm': 'lloyd',
Out[ ]:
'copy_x': True,
'init': 'k-means++',
'max_iter': 300,
'n_clusters': 2,
'n_init': 'warn',
'random_state': None,
'tol': 0.0001,
'verbose': 0}
experiment_number_of_clusters(X, KMeans())
2
∑ min(||xi − μj || )
μj ∈C
i=0
k-means minimiza esta medida, lo cual la hace una buena candidata para evaluar la calidad
de un cluster. Para esto ejecutamos k-means con diferentes valores de y graficamos el k
valor de la inercia. En esta gráfica buscamos un valor de tan pequeño como sea posible y
k
que tenga un valor de la métrica bajo. A este tipo de gráfica se le conoce usualmente como
gráfica de codo:
In [ ]: #@markdown **Video: Método del codo**
Out[ ]:
Para ilustrar este concepto, vamos a generar un modelo de agrupamiento para cada valor
de entre y . Al final de la generación, obtenemos el valor de la métrica de inercia con
k 2 15
el atributo intertia_ .
In [ ]: X,_ = make_blobs(500, cluster_std=1.5, centers=6, random_state=10)
sum_of_squared_distances = []
K = range(2,15)
for k in K:
km = KMeans(n_clusters=k)
km = km.fit(X)
sum_of_squared_distances.append(km.inertia_)
La gráfica de codo nos sugiere un valor de de 5 o 6. La razón es que hay un cluster mucho
k
más grande que el otro. Esto evidencia algunos de los problemas que tiene la inercia o suma
de distancia intra-cluster:
La inercia supone que los clusters son convexos e isotrópicos, lo que no siempre es así.
Responde mal a los grupos alargados, o múltiples con formas irregulares.
La inercia supone que los clusters son de tamaños similares, pues penaliza mucho más
fuertemente clusters grandes.
La inercia no es una métrica normalizada: solo sabemos que los valores más bajos son
mejores y que el cero es el óptimo.
3.1.2. Coeficiente de silueta
El coeficiente de silueta combina la distancia media intra-cluster ( ) y la distancia media al
a
b − a
si =
max(a, b)
Es una medida que está entre y para cada muestra. Un valor cercano a indica que la
−1 1 1
distancia inter-cluster es mucho más grande que la distancia intra-cluster. También indica
file:///Users/mac/Downloads/M2U4_Aprendizaje_no_supervisado__agrupamiento (1).html 48/73
11/5/23, 15:10 M2U4_Aprendizaje_no_supervisado__agrupamiento
que la muestra que estamos evaluando está en la frontera entre dos clusters.
Nota: Tenga en cuenta que el coeficiente de silueta solo tiene sentido cuando
2 <= k <= n con siendo el número de clusters y el tamaño de la
k n
muestra.
Para calcular el coeficiente de silueta del proceso de agrupamiento sklearn utiliza la media
de cada valor de silueta si
In [ ]: # Métricas de rendimiento
from sklearn.metrics import silhouette_score
K = range(2,15)
for k in K:
km = KMeans(n_clusters=k)
km = km.fit(X)
y = km.predict(X)
silhouette_scores.append(silhouette_score(X, y))
iris = load_iris()
X_iris, y_iris = iris.data, iris.target
Definimos la función plot_scores para graficar una métrica supervisada para varios
valores de . k
3.1.3.1. Homogeneidad
Para calcular la homogeneidad del proceso de agrupamiento, cada grupo es asociado con la
clase mayoritaria; luego, La métrica se evalúa contando el número de ejemplos clasificados
correctamente y dividiendo por N (Manning, Raghavan & Schütze, 2008).
En este caso está acotada entre y . Un valor cercano a nos indicará que las muestras
0 1 1
Podemos ver que se tendría que aplicar un análisis como el método del codo para
determinar el número óptimo de clusters. En este caso se puede observar que luego de 8
In [ ]: plot_extern_metric(X_iris, y_iris,
mutual_info_score, 'Información mutua')
Podemos ver que se tendría que aplicar un análisis como el método del codo para
determinar el número óptimo de clusters. En este caso podemos observar que el valor de
cambio es . En este caso la medida nos dice que al tener clusters, obtenemos casí el
7 7
El índice de Rand computa una medida de similitud entre dos agrupamientos al considerar
todas las parejas de ejemplos, contando el número de ejemplos que pertenecen al mismo
grupo y los que no en el agrupamiento real y en el predicho.
Scikit-learn implementa adjusted_rand_score en el paquete metrics . Esta
implementación es una versión corregida del índice de Rand que tiene en cuenta el
"chance", es decir la aleatoriedad de los agrupamientos. Agrupamientos aleatorios tienen un
índice de Rand ajustado cercanos a , con siendo un agrupamiento perfecto.
0 1
plot_extern_metric(X_iris, y_iris,
adjusted_rand_score, 'Índice de Rand ajustado')
Podemos ver que el índice de Rand es una métrica que buscamos máximizar, en este caso
escogeríamos .
k = 3
4.conectividad
Métodos jerárquicos
- basados en
file:///Users/mac/Downloads/M2U4_Aprendizaje_no_supervisado__agrupamiento (1).html 54/73
11/5/23, 15:10 M2U4_Aprendizaje_no_supervisado__agrupamiento
AgglomerativeClustering
Para los dos dataset anteriores los resultados obtenidos son apropiados, aunque requieren
de un buen uso de las métricas para obtener el número de clusters que se deben generar.
k
Los grupos en este dataset no son convexos, por lo que k-means no es el mejor
acercamiento al problema. Cuando los clusters no son globulares, otros métodos pueden
producir mejores resultados.
Los métodos de agrupamiento basados en conectividad utilizan relaciones de vecindad
entre los elementos para encontrar grupos. Estos métodos requieren construir una matriz
de conectividad de los puntos. La función kneighbors_graph del paquete neighbors
construye una matriz basada en los vecinos más cercanos de cada punto.
k
In [ ]: X, _ = make_moons(500, noise=.1)
Con la siguiente celda puede visualizar los K vecinos más cercanos de un punto
seleccionado al azar.
In [ ]: from sklearn.neighbors import kneighbors_graph
# Declaramos el modelo
ac = AgglomerativeClustering(connectivity=knn_graph, linkage="average")
plot_cluster_predictions(ac, X, n_clusters=2)
Cómo podemos ver, el método jerárquico se desempeña mucho mejor con las media lunas.
El algoritmo AgglomerativeClustering realiza un agrupamiento jerárquico de la
siguiente manera:
Cada ejemplo empieza en su propio grupo, y los grupos son fusionados iterativamente.
Los dos grupos que son fusionados en cada iteración dependen del criterio de
enlazamiento, el cuál es definido por el parámetro linkage .
En este caso usamos el criterio de enlazamiento promedio ( linkage = "average" ).
Este criterio minimiza el promedio de la distancia entre todos los ejemplos de cada par de
file:///Users/mac/Downloads/M2U4_Aprendizaje_no_supervisado__agrupamiento (1).html 57/73
11/5/23, 15:10 M2U4_Aprendizaje_no_supervisado__agrupamiento
grupos.
A continuación, podemos ver cómo los grupos encontrados por el algoritmo varía
dependiendo del tamaño de la vecindad.
In [ ]: experiment_hyerarchical(X, show_metric='silueta')
<class 'pandas.core.frame.DataFrame'>
Int64Index: 712 entries, 0 to 890
Data columns (total 8 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Embarked 712 non-null object
1 Sex 712 non-null object
2 Pclass 712 non-null int64
3 SibSp 712 non-null int64
4 Parch 712 non-null int64
5 Fare 712 non-null float64
6 Survived 712 non-null int64
7 Age 712 non-null float64
dtypes: float64(2), int64(4), object(2)
memory usage: 50.1+ KB
Como podemos ver, Embarked y Sex son variables categóricas y el resto son numéricas.
Esta información es necesaria para entender el ejemplo.
Antes de proceder con el preprocesamiento, convertimos los datos a la forma X, y .
Tenga en cuenta que en muchos casos no se cuenta con etiquetas en los ejercicios de
agrupamiento. Es decir, no se cuenta con un X y con un y . Sin embargo, en este ejemplo
file:///Users/mac/Downloads/M2U4_Aprendizaje_no_supervisado__agrupamiento (1).html 63/73
11/5/23, 15:10 M2U4_Aprendizaje_no_supervisado__agrupamiento
Observe que está vez no hemos convertido el DataFrame a un arreglo de Numpy, esto nos
facilitará el preprocesamiento más adelante.
La principal ventaja de esto es que nos permite usar los nombres de las características. De
igual manera, cómo veremos, no tendremos que preocuparnos por concatenar los datos
transformados (unos categóricos y otros numéricos).
5.2. Preprocesamiento
Para este ejemplo usaremos dos transformaciones conocidas: OneHotEncoder (para las
características categóricas) y StandardScaler (para las características numéricas).
Con el fin de simplificar el código usaremos ColumnTransformer . El objeto
ColumnTransformer es una utilidad que permite aplicar distintas transformaciones a
distintas columnas de un DataFrame de Pandas.
Primero, importamos las clases que necesitamos:
In [ ]: from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.compose import ColumnTransformer
Definimos dos listas, una con los nombres de las características categóricas y otra con las
características numéricas.
In [ ]: categoric = ['Embarked', 'Sex']
numeric = ['Pclass', 'SibSp', 'Parch', 'Fare', 'Age']
Donde el primer valor asigna el nombre de la transformación (lo usaremos más adelante), el
segundo valor de la tupla define el tipo de transformación con un objeto de sklearn y el
tercer valor corresponde a una lista con los nombres de las columnas a transformar.
En nuestro caso, definimos dos transformaciones:
onehot : One Hot Encoding para las características categóricas.
scaler : Estandarización para las características numéricas.
La intuición detrás de estandarizar las variables numéricas para KMeans proviene de que
KMeans por defecto utiliza una métrica de distancia euclidiana, la cual es sensible a las
unidades de las características. Es decir, una característica con alta varianza podría influir
más en los resultados del agrupamiento. Con la estandarización nos aseguramos de que
cada característica influye a la distancia de una manera similar.
Cómo regla general, debería probar el desempeño de un agrupamiento sin
preprocesamiento y compararlo con el desempeño de un agrupamiento con
preprocesamiento.
In [ ]: tf = ColumnTransformer([('onehot', OneHotEncoder(), categoric),
('scaler', StandardScaler(), numeric)])
Embarked cuenta con valores únicos y Sex con dos, es decir pasamos de
3 1
onehot_categories
In [ ]: X_preprocessed[0]
array([ 0. , 0. , 1. , 0. , 1. ,
Out[ ]:
0.90859974, 0.52251079, -0.50678737, -0.51637992, -0.52766856])
Los primeros valores corresponden a las variables del One Hot Encoding de Embarked
3 3
In [ ]: tf.named_transformers_['scaler']
# Datos originales
X_preprocessed[:5, 5:]
A partir de la evaluación del desempeño interno, podríamos concluir que un buen número
para es 3, el valor que maximiza el coeficiente de silueta.
k
A diferencia de la evaluación del desempeño interna, la externa nos sugiere usar un valor de
k más grande.
En este caso podríamos concluir que un buen valor para es , el valor que maximiza el
k 6
índice ajustado de Rand. Recuerde que el índice de Rand es una medida de similitud entre
los dos agrupamientos.
file:///Users/mac/Downloads/M2U4_Aprendizaje_no_supervisado__agrupamiento (1).html 69/73
11/5/23, 15:10 M2U4_Aprendizaje_no_supervisado__agrupamiento
Cabe aclarar que, la selección de depende del objetivo de análisis, si este tiene que ver
k
con la supervivencia es mejor quedarse con sugerido por los métodos de evaluación
k = 6
externa.
for i in range(k):
# Ejemplos que pertenecen al i-esimo grupo.
ids_group = y_pred == i
# retornamos un DataFrame
return pd.DataFrame(centroids, columns=columns)
Debido a los resultados de la evaluación del desempeño externa e interna, que indican que
3 y son valores apropiados para , mostramos los centroides para estas dos
6 k
configuraciones:
Visualizamos la matriz de contingencia junto con las funciones que se acaban de definir
para :
k = 3
In [ ]: show_survival_ratios(X_preprocessed, y_titanic, 3)
show_centroids(X_preprocessed, 3, tf)
Podemos darnos cuenta de que los centroides muestran el valor medio de cada
característica para las personas a el grupo.
En el caso de las variables categóricas, los valores del centroide corresponden a las
proporciones de personas con cada uno de los valores posibles.
Una observación que se puede realizar es sobre el grupo , este tiene la menor proporción
1
para k = 6:
In [ ]: show_contigency_matrix(X_preprocessed, y_titanic, 6, ['Survived: False', 'Survi
In [ ]: show_survival_ratios(X_preprocessed, y_titanic, 6)
show_centroids(X_preprocessed, 6, tf)
corresponden a pasajeros de primera clase y el valor promedio que pagaron por su tickete
es el más elevado ( ) de todos los grupos.
222.03463
Recursos adicionales
Los siguientes enlaces corresponden a sitios en donde encontrará información muy útil para
profundizar en el conocimiento de las funcionalidades de la librería Scikit-learn en el
desarrollo y evaluación de modelos de aprendizaje no supervisado como el agrupamiento,
además de material de apoyo teórico para reforzar estos conceptos:
Clustering - Scikit-learn
Hierarchial Clustering - Scikit-learn
Column Transformer for heterogeneous data - Scikit-learn
Data Mining Cluster Analysis: Basic Concepts and Algorithms - Introduction to Data
Mining by Tan, Steinbach, Karpatne, Kumar
Cluster Analysis in Data Mining
Referencias
Manning, C., Raghavan, D. & Schütze, H. (2008). Introduction to Information Retrieval
[Introducción a la recuperación de información].
Créditos
Profesor: Fabio Augusto Gonzalez
Asistentes docentes:
Miguel Angel Ortiz Marín
Alberto Nicolai Romero Martínez
Universidad Nacional de Colombia - Facultad de Ingeniería
In [ ]:
plt.style.use("ggplot")
Carga de Datos
In [ ]: time = np.random.uniform(0, 10, size=(1000, 1))
position = np.exp(-0.2 * time) * np.cos(2 * time) + np.random.normal(0, 0.1, si
In [ ]: fig, ax = plt.subplots()
ax.scatter(time, position, alpha=0.2)
ax.set(xlabel="Tiempo [s]", ylabel="Posicion [cm]")
Preprocesamiento
In [ ]: np.exp(1000)
file:///Users/mac/Downloads/grupo4.html 1/4
7/5/23, 16:00 grupo4
inf
Out[ ]:
In [ ]: np.exp(-0.1)
0.9048374180359595
Out[ ]:
x − min (x)
′
x =
max (x) − min (x)
In [ ]: scaler = MinMaxScaler().fit(time)
time_t = scaler.transform(time)
In [ ]: fig, ax = plt.subplots()
ax.scatter(time_t, position, alpha=0.2)
ax.set(xlabel="Tiempo [s]", ylabel="Posicion [cm]")
In [ ]: time_n = scaler.inverse_transform(time_t)
time_n.min(), time_n.max()
(0.003010875474882546, 9.98506355700189)
Out[ ]:
Validacion Cruzada
In [ ]: time_train, time_test, position_train, position_test = train_test_split(
time_t, position, test_size=0.3, random_state=0
file:///Users/mac/Downloads/grupo4.html 2/4
7/5/23, 16:00 grupo4
)
Modelamiento
In [ ]: model = SVR(gamma=100).fit(time_train, position_train)
/usr/local/lib/python3.9/dist-packages/sklearn/utils/validation.py:1143: DataC
onversionWarning: A column-vector y was passed when a 1d array was expected. P
lease change the shape of y to (n_samples, ), for example using ravel().
y = column_or_1d(y, warn=True)
Evaluacion
In [ ]: model.score(time_train, position_train)
0.9324830029391247
Out[ ]:
In [ ]: model.score(time_test, position_test)
0.9302732695254807
Out[ ]:
In [ ]: fig, ax = plt.subplots()
ax.scatter(time_t, position, alpha=0.2)
ax.plot(x_range, y_pred, color="k")
ax.set(xlabel="Tiempo [s]", ylabel="Posicion [cm]")
file:///Users/mac/Downloads/grupo4.html 3/4
7/5/23, 16:00 grupo4
In [ ]: position_train.mean()
0.008677297702295469
Out[ ]:
In [ ]: y_pred = model.predict(time_test)
np.sqrt(mean_squared_error(position_test, y_pred))
0.09755202307869525
Out[ ]:
file:///Users/mac/Downloads/grupo4.html 4/4