Laboratorio 6 - Parte 2: Reducción de dimensión PCA y LDA#

!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="L06.02", varname="student");
#configuración del laboratorio
# Ejecuta esta celda!
from Labs.commons.utils.lab6 import *
_, x, y = part_2()

Para el problema de clasificación usaremos la siguiente base de datos: https://archive.ics.uci.edu/ml/datasets/Cardiotocography

Analice la base de datos, sus características, su variable de salida y el contexto del problema.

print('Dimensiones de la base de datos de entrenamiento. dim de X: ' + str(np.shape(x)) + '\tdim de Y: ' + str(np.shape(y)))

Este ejercicio tiene como objetivo implementar varias técnicas de extracción de características (PCA y LDA)

observación para las librerias sklearn

Llamar explicitamente los parametros de las librerias de sklearn (e.j. si se quiere usar el parametro kernel del SVC, se debe llamar SVC(kernel='rbf')

En la siguiente celda se define una función para entrenar un SVM para resolver el problema. Esta función la vamos a usar como base para comparar nuestros métodos de selección de características.

def entrenamiento_sin_seleccion_caracteristicas(splits, X, Y):
    """
    Función que ejecuta el entrenamiento del modelo sin una selección particular
    de las características

      Parámetros:
        splits : número de particiones  a realizar
      Retorna:
        - El vector de errores
        - El Intervalo de confianza
        - El tiempo de procesamiento
    """
    #Implemetamos la metodología de validación
    Errores = np.ones(splits)
    Score = np.ones(splits)
    times = np.ones(splits)
    j = 0
    kf = KFold(n_splits=splits)
    for train_index, test_index in kf.split(X):
        X_train, X_test = X[train_index], X[test_index]
        y_train, y_test = Y[train_index], Y[test_index]
        scaler = StandardScaler()
        X_train = scaler.fit_transform(X_train)
        X_test = scaler.transform(X_test)
        #Creamos el clasificador SVM.
        clf = SVC(kernel="linear", C=1)
        #Aquí se entran y se valida el modelo sin hacer selección de características
        tiempo_i = time.time()
        clf.fit(X_train,y_train)
        # Validación del modelo
        Errores[j] = accuracy_score(y_true=y_test, y_pred=clf.predict(X_test))
        times[j] = time.time()-tiempo_i
        j+=1

    return np.mean(Errores), np.std(Errores), np.mean(times)

Ejercicio 1: Entrenamiento usando PCA para realizar extracción#

En este ejercicio vamos a aplicar PCA para realizar la extracción de características. Para ello se debe tener en cuenta:

  1. Vamos a usar el módulo PCA de sklearn, que ya se encuentra importado (se pueda acceder a el como PCA(....))

  2. Tener en cuenta la respuesta de la siguiente pregunta abierta y completar el código de acuerdo a la respuesta usando la librería y módulo de sklearn correspondiente (que también debería ya estar importado en la configuración).

  3. Usar el parámetro adecuado para las particiones en la metodología de validación

  4. Usar la exactitud como medida de error del módulo metrics de sklearn

  5. Vamos a calcular el costo computacional de aplicar PCA.

  6. Recordar que PCA se debe “ajustar” con el conjunto de entrenamiento. Pero la transformación se debe hacer para las particiones de entrenamiento y test.

#@title Pregunta Abierta
#@markdown Cuando se aplica PCA ¿es necesario estandarizar los datos? ¿En qué consiste dicha estandarización?
respuesta = '' #@param {type:"string"}
#ejercicio de código
def entrenamiento_pca_ext_caracteristicas(n_comp, n_sets, X, Y):
    """
    Esta función realiza la reducción de la dimensionalidad sobre el conjunto de
    datos de entrenamiento, de acuerdo con las particiones especificadas usando PCA

    Parámetros:
        n_comp, int, Número de componentes para reducción
        n_sets,int, Número de particiones
        X: numpy Array de características
        Y: numpy Array  Vector de etiquetas

    Retorna:
        El valor medio de errores
        Intervalo de confianza del error
        El  valor medio del tiempo de ejecución
    """
    #Implemetamos la metodología de validación
    Errores = np...
    times = np...
    j = 0
    kf = KFold(...)
    for train_index, test_index in kf.split(X):
        X_train, X_test = X[train_index], X[test_index]
        y_train, y_test = Y[train_index], Y[test_index]

        # ¿es necesario estandarizacion de datos?
        ...
        X_train = ....
        X_test = ...

        #dejar el mismo nombre del objeto
        pca = ...
        # para calcular costo computacional
        tiempo_i = time.time()
        # es recomendable usar el metodo que ajusta y transforma
        X_train_pca = ...
        # aca solo usar el metodo de transformar (ya que en el anterior el pca se ajusto)
        X_test_pca = ...
        # entrenar el modelo usando las caractieristicas transformadas por PCA
        clf = ....
        clf.fit(X=..., y=y_train)
        tiempo_o = time.time()-tiempo_i
        Errores[j] = ...(y_true=y_test, y_pred=....predict(...))
        times[j] = tiempo_o
        j+=1


    return

Registra tu solución en línea

student.submit_task(namespace=globals(), task_id='T1');

Ejercicio 2 : Experimentar con PCA#

Usando las anteriores funciones vamos a realizar experimentos para evaluar la efectividad de PCA, para ello:

  1. Utilizar una metodología cross-validation con 5 particiones.

  2. Usar como parámetros para los experimentos el número de características a extraer

  3. Usar la función entrenamiento_pca_ext_caracteristicas para realizar la extración de características.

  4. Vamos a retornar un DataFrame con las siguientes columnas:

    • CON_SEL: indicando si se uso selección de características

    • NUM_VAR: número de selección de características

    • T_EJECUCION: tiempo de ejecucción

    • ERROR_VALIDACION

    • STD_ERROR_VALIDACION

  5. En la primera fila del dataframe vamos a incluir la evaluación del modelo SVM sin selección de características (usando la función creada en el primer ejercicio).

#ejercicio de código
def experimentar_PCA(n_feats, X, Y):
    """
    Esta función realiza la comparación del desempeño de PCA utilizando diferente
    número de caracteristicas y particionando el conjunto de datos en 5 conjuntos

    Parámetros:
        X (numpy.array), El arreglo numpy de características
        Y (numpy.array), El vector de etiquetas
        n_feats, Vector de números enteros que indica el número de características
                que debe utilizar el modelo

    Retorna:
    - DataFrame con las columnas: CON_SEL, NUM_VAR, T_EJECUCION, ERROR_VALIDACION y IC_STD_VALIDACION.

    """
    df = pd.DataFrame()
    idx = 0
    split_number = 5
    #Sin selección de características
    error,ic_error,t_ex = ...
    df.loc[idx,'CON_SEL'] = 'NO'
    df.loc[idx,'NUM_VAR'] = ...
    df.loc[idx,'T_EJECUCION'] = ...
    df.loc[idx,'ERROR_VALIDACION'] = ...
    df.loc[idx,'STD_ERROR_VALIDACION'] = ...
    idx+=1
    print("termina experimento sin selección")
    #Con selección de características

    for f in n_feats:
        #Implemetamos la metodología de validación
        ..., ..., ... = ...(n_comp=f, X=...,Y=... n_sets...)
        df.loc[idx,'CON_SEL'] = 'SI'
        df.loc[idx,'NUM_VAR'] = ...
        df.loc[idx, 'T_EJECUCION'] = ...
        df.loc[idx,'ERROR_VALIDACION'] = ...
        df.loc[idx, 'STD_ERROR_VALIDACION'] = ...
        idx+=1
    return

Registra tu solución en línea

student.submit_task(namespace=globals(), task_id='T2');
experimentar_PCA(n_feats=[2,5,10,15,20], X= x, Y = y)
# aca realizamos una curva de varianza explicada del PCA
pca_varianza = PCA(n_components=x.shape[1]).fit(StandardScaler().fit_transform(x))
plt.plot(np.cumsum(pca_varianza.explained_variance_/np.sum(pca_varianza.explained_variance_)))
plt.axvline(x=2.0, c= 'r')
plt.axvline(x=5.0, c= 'r')
plt.axvline(x=13, c= 'r')
plt.axvline(x=11, c= 'r')
plt.axvline(x=20, c= 'r')
plt.title('Varianza acumulada')
plt.xlabel('Componentes principales')
plt.ylabel('Porcentaje de varianza acumulada')
plt.grid()

Ahora recordemos que PCA también nos sirve para explorar y visualizar los datos en pocas dimensiones. En la siguiente celda vamos a visualizar nuestro conjunto de datos usando los dos primeros componentes principales

data_to_plot = StandardScaler().fit_transform(X=x)
fig, ax = plt.subplots()
pca = PCA(n_components=2)
x_pc2 = pca.fit_transform(data_to_plot)
scatter= ax.scatter(x= x_pc2[:,0], y = x_pc2[:,1], c = y, alpha = 0.5, label = y)
legend1 = ax.legend(*scatter.legend_elements(),
                    loc="lower left", title="Classes")
ax.add_artist(legend1)
plt.xlabel("PC1"); plt.ylabel("PC2")
plt.show()
#@title Pregunta Abierta
#@markdown Aunque PCA nos nos ofrece una visualización aproximada de nuestro conjunto de datos, conociendo la varianza acumulada obtenida para 2 componentes principales ¿qué tan cercana es la aproximación para este problema en específico?
respuesta = '' #@param {type:"string"}

En nuestros laboratorios anteriores, hemos usado el siguiente código:

digits = load_digits(n_class=5)
#--------- preprocesamiento--------------------
pca = PCA(n_components = 0.99, whiten=True)
print("shape antes pca", digits.data.shape)
data = pca.fit_transform(digits.data)
print("shape luego pca", data.shape)

Aplicando los conceptos que manejamos en este laboratorio, responde la siguiente pregunta abierta

#@title Pregunta Abierta
#@markdown En nuestros laboratorios pasados y usando el código ejecutado anteriormente ¿Las 40 características representaban bien la varianza del conjunto original?
respuesta = '' #@param {type:"string"}

Ejercicio 3: Entrenamiento usando Discriminante de Fisher para extracción#

En este ejercicio vamos a aplicar LDA para realizar la extracción de características. Para ello tener en cuenta:

  1. Vamos a usar el modulo LinearDiscriminantAnalysis-LDA de sklearn. El cual ya se encuentra importado (se pueda acceder a el como LinearDiscriminantAnalysis(....))

  2. ¿También se estandarizar los datos?

  3. Usar 5 particiones en la metodologia de validación

  4. Usar la exactitud/accuracy como medida de desempeño del módulo metrics de sklearn

  5. Vamos a calcular el costo computacional de aplicar la LDA.

  6. Recordar que LDA se debe “ajustar” con el conjunto de entrenamiento. Pero la transformación se debe hacer para las particiones de entrenamiento y test.

#@title Pregunta Abierta
#@markdown Explicar en sus palabras la principal ventaja que tiene LDA sobre PCA para resolver problemas de clasificación.
respuesta = '' #@param {type:"string"}
#ejercicio de código
def entrenamiento_lda_ext_caracteristicas(n_comp, X, Y):
    """
    Esta función realiza la reducción de la dimensionalidad sobre el conjunto de
    datos de entrenamiento, de acuerdo con las particiones especificadas usando PCA

    Parámetros:
        n_comp, int, Número de componentes para reducción
        X: numpy Array de características
        Y: numpy Array  Vector de etiquetas

    Retorna:
        tupla con:
        El  valor medio del tiempo de ejecución,
        El valor medio de exactitud
        Intervalo de confianza de la exactitud
    """


    #Implemetamos la metodología de validación
    Errores = np.ones(5)
    times = np.ones(5)
    j = 0
    kf = KFold(...)
    for train_index, test_index in kf.split(X):
        X_train, X_test = ...
        y_train, y_test = ...

        # ¿es necesario estandarizacion de datos?
        ...
        X_train = ....
        X_test = ...
        # dejar el nombre del objeto igual (lda)
        lda = ...(n_components=...)
        # para calcular costo computacional
        tiempo_i = time.time()
        # es recomendable usar el metodo que ajusta y transforma
        X_train_lda = lda..
        # aca solo usar el metodo de transformar (ya que en el anterior el pca se ajusto)
        X_test_lda = lda...
        # entrenar el modelo usando las caractieristicas transformadas por PCA
        clf = SVC(kernel="linear", C=1)
        clf.fit(X=X_train_lda, y=...)
        tiempo_o = time.time()-tiempo_i
        Errores[j] = ...
        times[j] = tiempo_o
        j+=1


    return

Registra tu solución en línea

student.submit_task(namespace=globals(), task_id='T3');

Ejercicio 4 : Experimentar con Discriminante de Fisher#

Usando las anteriores funciones vamos a realizar experimentos para evaluar la efectividad de PCA, para ello:

  1. Utilizar una metodología cross-validation con 5 particiones.

  2. Usar como parámetros para los experimentos el número de características a extraer

  3. Usar la función entrenamiento_pca_ext_caracteristicas para realizar la extración de características.

  4. Vamos a retornar un DataFrame con las siguientes columnas:

    • CON_SEL: indicando si se uso selección de características

    • NUM_VAR: número de selección de caracteristicas

    • ERROR_VALIDACION

    • STD_ERROR_VALIDACION

    • T_EJECUCION: tiempo de ejecucción

  5. En la primera fila del dataframe vamos a incluir la evaluación del modelo SVM sin selección de características (usando la función creada en el primer ejercicio).

#ejercicio de código
def experimentar_LDA(n_feats, X, Y):
    """
    Esta función realiza la comparación del desempeño de LDA utilizando diferente
    número de feats y particionando el conjunto de datos en diferente en 5 subconjuntos

    Parámetros:
    X (numpy.array), El arreglo numpy de características
    Y (numpy.array), El vector de etiquetas
    n_feats, Vector de números enteros que indica el número de características
              que debe utilizar el modelo

    Retorna:
    - DataFrame con las columnas: CON_SEL, NUM_VAR, ERROR_VALIDACION, IC_STD_VALIDACION,
    y T_EJECUCION.

    """

    df = pd.DataFrame()
    idx = 0
    split_number = 5
    #Sin selección de características
    ...,...,... = ...(split_number, X,Y)
    df.loc[idx,'CON_SEL'] = 'NO'
    df.loc[idx,'NUM_VAR'] = X.shape[1] # se usan todas las caracteristicas
    df.loc[idx,'ERROR_VALIDACION'] = ...
    df.loc[idx,'STD_ERROR_VALIDACION'] = ...
    df.loc[idx,'T_EJECUCION'] = ...
    idx+=1
    print("termina experimento sin selección")
    #Con selección de características

    for f in n_feats:
        #Implemetamos la metodología de validación
        ..., ..., ... = ...(n_comp=f, X=x,Y=y)
        df.loc[idx,'CON_SEL'] = 'SI'
        df.loc[idx,'NUM_VAR'] = ...
        df.loc[idx,'ERROR_VALIDACION'] = ...
        df.loc[idx, 'STD_ERROR_VALIDACION'] = ...
        df.loc[idx, 'T_EJECUCION'] = ...
        idx+=1
    return df

Registra tu solución en línea

student.submit_task(namespace=globals(), task_id='T4');
experimentar_LDA(n_feats=[1,2], X= x, Y = y)