Laboratorio 3 - Parte 2. Comparación de metodos basados en árboles#
!wget -nc --no-cache -O init.py -q https://raw.githubusercontent.com/jdariasl/Intro_ML_2025/master/init.py
import init; init.init(force_download=False); init.get_weblink()
from local.lib.rlxmoocapi import submit, session
import inspect
session.LoginSequence(endpoint=init.endpoint, course_id=init.course_id, lab_id="L03.02", varname="student");
#configuración del laboratorio
# Ejecuta esta celda!
from Labs.commons.utils.lab3 import *
_ = part_2()
A continuación se leen los datos de un problema de clasificación. El problema corresponde a la clasifiación de dígitos escritos a mano, el cual fue abordado en el laboratorio anterior. Usaremos únicamente 4 de las 10 clases disponibles, usando solo los números pares. Nuevamente, los datos fueron preprocesados con PCA para reducir el número de características.
digits = load_digits(n_class=10)
#--------- preprocesamiento usando solo los pares--------------------
pca = PCA(0.99, whiten=True)
data = pca.fit_transform(digits.data[np.isin(digits.target, [2,4,6,8,10])])
#---------- Datos a usar ----------------------
x = data
y = digits.target[np.isin(digits.target, [2,4,6,8,10])]
Ejercicio 1 Experimentos con Arboles de decisión#
Debe consultar todo lo relacionado con la creación, entrenamiento y uso en predicción del modelo conocido como árbol de decisión usando la librería scikit-learn. En este enlace, se puede leer la documentación http://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html.
En el notebook, ya se encuentra cargada la libreria:
from sklearn.tree import DecisionTreeClassifier
Las siguientes preguntas abiertas, buscan verificar que se está haciendo un contraste con la librería y la teoría, por lo tanto procura incluir conceptos asociados y NO solo enfocarse en las descripciones de la documentación.
#@title Pregunta Abierta
#@markdown ¿Qué efecto tienen los parámetros min_samples_split y max_depth definidos en la librería?
respuesta = "" #@param {type:"string"}
#@title Pregunta Abierta
#@markdown ¿Cuál es la diferencia entre min_samples_leaf y min_samples_split? Y explique la diferencia fundamental de estos dos con respecto a min_impurity_decrease.
respuesta = "" #@param {type:"string"}
En la siguiente celda se define una simulación para entrenar y validar un modelo usando los datos previamente cargados. Complete el código para usar como modelo de predicción un arbol de decisión.
Note que existe una clase para modelos de clasificación y otra para modelos de regresión: http://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeRegressor.html
Vamos a tener en cuenta lo siguiente:
dentro del código, ya se encuentra sugerida la metodologia de validación
la función va aceptar un parametro booleano, dependiendo del valor de esta parametro, se ejecutara normalización de los datos.
hacer uso explicito del nombre del parametro que se va usar, por ejemplo, si se requeire asignar el parametro
max_features
debemos llamar la libreria de esta manera:DecisionTreeClassifier(max_features = 'auto')
Vamos a configurar el arbol con la medida de impureza Gini
#ejercicio de código
def experimentar_dt( X, Y, depths,normalize):
"""función que realiza experimentos con árboles de decisión
X: matriz con las características
Y: matriz de numpy con etiquetas
depths: list[int] lista con la profundidad de arboles a experimentar
normalize bool: indica si se aplica normalización a los datos
retorna: dataframe con:
- profunidad de los árboles
- eficiencia de entrenamiento
- desviación estandar de la eficiencia de entrenamiento
- eficiencia de prueba
- desviación estandar de la eficiencia de prueba
"""
folds = 4
skf = StratifiedKFold(n_splits=folds)
resultados = pd.DataFrame()
idx = 0
for depth in depths:
## para almacenar los errores intermedios
EficienciaTrain = []
EficienciaVal = []
for train, test in skf.split(X, Y):
Xtrain = X[train,:]
Ytrain = Y[train]
Xtest = X[test,:]
Ytest = Y[test]
#Normalizamos los datos
# si la bandera esta en True
if normalize:
scaler = StandardScaler()
scaler.fit(Xtrain)
Xtrain= scaler.transform(Xtrain)
Xtest = scaler.transform(Xtest)
#Haga el llamado a la función para crear y entrenar el modelo usando los datos de entrenamiento
#Ajuste la semilla en 0 para garantizar la reproducibilidad de los resultados
modelo =
modelo
#predecir muestras de entrenamiento
Ytrain_pred = modelo
#predecir muestras de pruebas
Yest = modelo
#Evaluamos las predicciones del modelo con los datos de test
EficienciaTrain.append(np.mean(Ytrain_pred.ravel() == Ytrain.ravel()))
EficienciaVal.append(np.mean(Yest.ravel() == Ytest.ravel()))
resultados.loc[idx,'profunidad del arbol'] = depth
resultados.loc[idx,'eficiencia de entrenamiento'] =
resultados.loc[idx,'desviacion estandar entrenamiento'] =
resultados.loc[idx,'eficiencia de prueba'] =
resultados.loc[idx,'desviacion estandar prueba'] =
idx= idx +1
return (resultados)
Registra tu solución en línea
student.submit_task(namespace=globals(), task_id='T1');
# Realiza los experimentos sin normalizacion
depths = [5,10,20,30,50]
resultados_dt_no_norm = experimentar_dt(X = x , Y = y, depths = , normalize=)
resultados_dt_no_norm
# Realiza los experimentos con normalizacion
depths = [5,10,20,30,50]
resultados_dt_norm = experimentar_dt(X = x , Y = y, depths = , normalize=)
resultados_dt_norm
#@title Pregunta Abierta
#@markdown ¿Tiene algún efecto la normalización o estándarización de las variables en el desempeño del modelo de árboles de decisión? Justifique.
respuesta = "" #@param {type:"string"}
Ejercicio 2 Experimentos con Random Forest#
En la siguiente celda se define una simulación para entrenar y validar un modelo usando los datos previamente cargados. Complete el código para usar como modelo de predicción un Random Forest. Debe consultar todo lo relacionado con la creación, entrenamiento y uso en predicción de este modelo usando la librería scikit-learn. Consultar aquí: http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html.
En el notebook, ya se encuentra cargada la clase:
from sklearn.ensemble import RandomForestClassifier
Note que al igual que en el caso anterior, existe una clase para modelos de clasificación y otra para modelos de regresión: http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestRegressor.html
**Recorde que para instancias un objeto de la clase no se usan parámetros posicionales; todo los parámetros deben ser llamados por su nombre.
Para nuestros experimentos vamos a configurar el RF para que el mínimo de muestras a considerar en un nodo hoja sea 3.
#ejercicio de código
def experimentar_rf(X, Y, num_trees,numero_de_variables):
"""función que realiza experimentos con el modelo random forest
X: matriz con las caractersiticas
Y: matriz de numpy con etiquetas
num_trees: list[int]: lista con el número de arboles usado para el RF
numero_de_variables list[int]: lista con variables para la selección del mejor umbral en cada nodo
retorna: dataframe con:
- numero de arboles usados
- variables para la selección del mejor umbral
- eficiencia de entrenamiento
- desviación de estandar de la eficiencia de entrenamiento
- eficiencia de prueba
- desviación estandar de la eficiencia de prueba
"""
folds = 4
skf = StratifiedKFold(n_splits=folds)
resultados = pd.DataFrame()
idx = 0
for trees in num_trees:
for num_variables in numero_de_variables:
## para almacenar los errores intermedios
EficienciaTrain = []
EficienciaVal = []
for train, test in skf.split(X, Y):
Xtrain = X[train,:]
Ytrain = Y[train]
Xtest = X[test,:]
Ytest = Y[test]
#Haga el llamado a la función para crear y entrenar el modelo usando los datos de entrenamiento
#Ajuste la semilla en 0 para garantizar la reproducibilidad de los resultados
modelo =
modelo
#predecir muestras de entrenamiento
Ytrain_pred = modelo
#predecir muestras de pruebas
Yest = modelo
#Evaluamos las predicciones del modelo con los datos de test
EficienciaTrain.append(np.mean(Ytrain_pred.ravel() == Ytrain.ravel()))
EficienciaVal.append(np.mean(Yest.ravel() == Ytest.ravel()))
resultados.loc[idx,'número de arboles'] = trees
resultados.loc[idx,'variables para la selección del mejor umbral'] = num_variables
resultados.loc[idx,'eficiencia de entrenamiento'] =
resultados.loc[idx,'desviacion estandar entrenamiento'] =
resultados.loc[idx,'eficiencia de prueba'] =
resultados.loc[idx,'desviacion estandar prueba'] =
idx= idx +1
print(f"termina para {trees} arboles")
return (resultados)
Registra tu solución en línea
student.submit_task(namespace=globals(), task_id='T2');
Una vez completado el código realice los experimentos necesarios para llenar la siguiente tabla:
arboles = [5,10,20,50,100, 150]
variables_seleccion = [5,20,40]
resultados_rf = experimentar_rf(X=x, Y=y, num_trees = ,numero_de_variables = )
resultados_rf
Vamos a comparar los resultados del RF con los del DT.
print("diferencia promedio entre entrenamiento y prueba del DT",
resultados_dt_norm['eficiencia de entrenamiento'].mean()-resultados_dt_norm['eficiencia de prueba'].mean())
print("diferencia promedio entre entrenamiento y prueba del RF",
resultados_rf['eficiencia de entrenamiento'].mean()-resultados_rf['eficiencia de prueba'].mean())
Ejercicio 3 Experimentos con Gradient Boosted Trees#
En la siguiente celda se define una simulación para entrenar y validar un modelo usando los datos previamente cargados. Complete el código para usar como modelo de predicción un Gradient boosted Tree. Debe consultar todo lo relacionado con la creación, el entrenamiento y el uso en predicción de este modelo usando la librería scikit-learn. Consultar aquí: https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.GradientBoostingClassifier.html
En el notebook, ya se encuentra cargada la libreria:
from sklearn.ensemble import GradientBoostingClassifier
Debemos configurar los árboles con un mínimo de tres (3) muestras para considerar la división de un nodo.
Note que al igual que en el caso anterior, existe una clase para modelos de clasificación y otra para modelos de regresión: https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.GradientBoostingRegressor.html#sklearn.ensemble.GradientBoostingRegressor
#ejercicio de código
def experimentar_gbt(num_trees, X, Y):
"""funcion que realiza experimentos de arboles de decision
num_trees: list[int] lista con el número de arboles usado para el RF
X: matriz con las caractersiticas
Y: matriz de numpy con etiquetas
retorna: dataframe con:
- numero de arboles usados
- eficiencia de entrenamiento
- desviacion de estandar eficiencia de entrenamiento
- eficiencia de prueba
- desviacion estandar eficiencia de prueba
"""
folds = 4
skf = StratifiedKFold(n_splits=folds)
resultados = pd.DataFrame()
idx = 0
for trees in num_trees:
## para almacenar los errores intermedios
EficienciaTrain = []
EficienciaVal = []
for train, test in skf.split(X, Y):
Xtrain = X[train,:]
Ytrain = Y[train]
Xtest = X[test,:]
Ytest = Y[test]
#Haga el llamado a la función para crear y entrenar el modelo usando los datos de entrenamiento
#Ajuste la semilla en 0 para garantizar la reproducibilidad de los resultados
modelo=
modelo
#predecir muestras de entrenamiento
Ytrain_pred =
#predecir muestras de pruebas
Yest =
#Evaluamos las predicciones del modelo con los datos de test
EficienciaTrain.append(np.mean(Ytrain_pred.ravel() == Ytrain.ravel()))
EficienciaVal.append(np.mean(Yest.ravel() == Ytest.ravel()))
resultados.loc[idx,'número de arboles'] = trees
resultados.loc[idx,'eficiencia de entrenamiento'] =
resultados.loc[idx,'desviacion estandar entrenamiento'] =
resultados.loc[idx,'eficiencia de prueba'] =
resultados.loc[idx,'desviacion estandar prueba'] =
idx= idx +1
return (resultados)
Registra tu solución en línea
student.submit_task(namespace=globals(), task_id='T3');
# ejecuta para realizar los experimentos
arboles = [5,10,20,50,100, 150]
resultados_gbt = experimentar_gbt(arboles, x, y)
resultados_gbt
Vamos a graficar la eficiencia para el RF y el GBT en función del número de arboles.
# se crea un df para agrupar los resultados
# y graficar las diferencias entre el GBT y el RF
import seaborn as sns
rf_res = resultados_rf.groupby("número de arboles")['eficiencia de prueba'].mean().reset_index()
rf_res['Tipo'] = 'RF'
gbt_res = resultados_gbt.groupby("número de arboles")['eficiencia de prueba'].mean().reset_index()
gbt_res['Tipo'] = 'GBT'
data_to_plot= pd.concat([rf_res, gbt_res], ignore_index=True)
sns.relplot(data=data_to_plot, x= 'número de arboles', y = 'eficiencia de prueba', hue = 'Tipo', kind='line', aspect=1.5,height=3)
plt.show()
Ejercicio 4 Tiempo de entrenamiento del RF y GBT#
En nuestro último experimento, vamos a evaluar la influencia de los parámetros del RF y del GBT en el tiempo de entrenamiento.
Para ello vamos a crear una función para medir el tiempo de entrenamiento usando la instrucción time.process_time()
.
Vamos crear la función, para poder evaluar la influencia de:
número de árboles
cantidad de variables a analizar por nodo
En el entrenamiento del RF y del GBT.
Notar
No vamos a dividir el conjunto de muestras ya que el objetivo es evaluar el tiempo de entrenamiento y no la eficiencias del modelo
No calcularemos las prediciones
#ejercicio de código
def time_rf_gbt_training(X, Y, num_trees, numero_de_variables, metodo):
"""función que realiza experimentos para determinar la influencia
del número de árboles y de características por nodo en el tiempo de entrenamiento
del RF
X: conjunto de datos para realizar los experimentos
Y: conjunto de etiquetas de clase
num_trees: List[int] lista con el número de arboles a evaluar
num_variables: List[int] lista con el número variables a evaluar
metodo: 'rf' o 'gbt', de acuerdo a esto se verifica cual modelo a evaluar.
retorna: dataframe con:
- número de arboles
- variables para la selección del mejor umbral
- tiempo de entrenamiento (promedio)
"""
resultados = pd.DataFrame()
idx = 0
for trees in num_trees:
for variables in numero_de_variables:
## ejecutar 5 veces lo mismo
## para llegar a un tiempo más adecuado
tiempos = []
for i in range(5):
## llamar la funcion para inicar el conteo
start
#Ajuste la semilla en 0 para garantizar la reproducibilidad de los resultados
if metodo == 'rf':
modelo =
else:
modelo =
modelo
## obtener tiempo
end
# append de la resta de fin y end
tiempos.append()
resultados.loc[idx,'numero de arboles'] = trees
resultados.loc[idx,'variables para la seleccion del mejor umbral'] = variables
# obtenga el promedio
resultados.loc[idx,'tiempo de entrenamiento'] =
resultados.loc[idx,'metodo'] = metodo
idx = idx +1
return(resultados)
Registra tu solución en línea
student.submit_task(namespace=globals(), task_id='T4');
Vamos a dejar fijo el número de variables en 20 y variar los árboles en: [5,10,15,25, 50], completa el código para ver la gráfica
resultados_rf_time1 = time_rf_gbt_training(x, y, [], [], metodo = 'rf')
resultados_gbt_time1 = time_rf_gbt_training(x, y, [], [], metodo = 'gbt')
resultados_time = pd.concat([resultados_rf_time1, resultados_gbt_time1], ignore_index=True)
sns.relplot(data = resultados_time, x = 'numero de arboles', y = 'tiempo de entrenamiento', hue = 'metodo', kind = 'line')
Y por ultimo vamos a dejar fijo el número de árboles en 20 y el número de varaibles [5,10,15,20,40], completa el código para ver la gráfica
resultados_rf_time1 = time_rf_gbt_training(x, y, [], [], metodo = 'rf')
resultados_gbt_time1 = time_rf_gbt_training(x, y, [], [], metodo = 'gbt')
resultados_time = pd.concat([resultados_rf_time1, resultados_gbt_time1], ignore_index=True)
sns.relplot(data = resultados_time, x = 'variables para la seleccion del mejor umbral', y = 'tiempo de entrenamiento', hue = 'metodo', kind = 'line')
#@title Pregunta Abierta
#@markdown Cuál parámetro de los evaluados tiene una mayor influencia en los tiempos de entrenamiento? ¿Porqué?
respuesta = "" #@param {type:"string"}