UNIVERSIDAD NACIONAL AUTÓNOMA DE MÉXICO
____________________________________________________
INSTITUTO DE INVESTIGACIONES EN MATEMÁTICAS APLICADAS
Y SISTEMAS (IIMAS)
Práctica 3: Selección de Características
MATERIA
Reconocimiento de Patrones
Ciencia de Datos
ALUMNO
Erick José Fabián Sandoval
PROFESORA
Ph. D. María Elena Martínez Perez
AYUDANTE
M. en C. Miguel Angel Veloz Lucas
Ciudad Universitaria, Cd. Mx., 2025
Fabián Sandoval
Reconocimiento de Patrones
—------------------------------------------------------------------------------------------------------------------------
1. Reglas generales para el desarrollo de las Prácticas de Laboratorio
❖ Deberás respetar la estructura general de este documento, i.e., entregar tu práctica con
las secciones: objetivos, introducción, desarrollo, código,conclusiones y referencias.
❖ El desarrollo de la práctica deberá ser auténtico. Aquellos equipos que presenten los
mismos cálculos, código fuente, etcétera, serán sancionados.
❖ El día de entrega establecido deberá ser respetado por todos los equipos. La hora límite
de entrega es la hora de clase y no se reciben trabajos que sean terminados durante la
hora de clase.
❖ Deberás entregar el documento en el classroom antes de la fecha límite.
2. Objetivos
❖ Implementar diferentes métodos de selección de características.
❖ Comparar resultados entre distintos métodos de selección de características.
❖ Analizar el impacto de la reducción dimensional.
3. Introducción
La selección de características es fundamental en el campo del reconocimiento de
patrones y el aprendizaje automático. Su propósito radica en identificar las variables o atributos
más informativos dentro de un conjunto de datos, descartando aquellos que son redundantes,
irrelevantes o ruidosos. Este proceso no solo mejora la eficiencia computacional, sino que
también eleva la capacidad de generalización de los modelos, permitiéndoles identificar patrones
subyacentes, evitando el sobreajuste (overfitting). Este proceso consiste en identificar el
equilibrio entre la simplificación y la optimización: trabajar con menos datos, pero de mayor
calidad.
3.1. La Importancia de la Selección de Características
En problemas de alta dimensionalidad, donde el número de características puede superar
ampliamente la cantidad de muestras, la selección de estas características se vuelve crítica. Por
ejemplo, en imágenes médicas o datos genómicos, es común tener miles de variables, muchas de
las cuales pueden ser correlacionadas o carecer de valor predictivo. Al reducir la
dimensionalidad, los algoritmos evitan considerar información irrelevante, enfocándose en los
atributos clave que definen los patrones. Además, modelos más simples son más interpretables,
un aspecto que sobresale en áreas como la medicina o las ciencias sociales, donde entender por
qué un modelo toma una decisión es tan importante como su precisión.
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
1
IIMAS, UNAM
Fabián Sandoval
Reconocimiento de Patrones
—------------------------------------------------------------------------------------------------------------------------
3.2. Desafíos y Consideraciones Prácticas
La selección de características continúa teniendo muchos retos. Uno de los más
significativos es el manejo de relaciones no lineales o complejas entre variables. Por ejemplo, en
problemas de visión artificial, la textura de una imagen puede depender de la interacción no
aditiva entre píxeles vecinos, algo que métodos lineales como la correlación podrían pasar por
alto. Pero técnicas basadas en métodos no paramétricos (como el análisis de componentes
independientes) pueden ser más apropiadas.
Otro desafío es la estabilidad, en donde conjuntos de datos con alto nivel de ruido o muestras
limitadas pueden variar significativamente los subconjuntos seleccionados entre particiones de
entrenamiento y validación. Esto afecta a la confiabilidad del modelo, especialmente en
aplicaciones críticas como el diagnóstico médico. Para mitigarlo, se recomienda usar técnicas de
validación cruzada robustas o métodos de consenso. Adicionalmente, es crucial evitar un
enfoque limitado que priorice características individualmente relevantes pero descarte grupos
complementarios. Como puede ser el caso del procesamiento de lenguaje natural (NLP),
palabras como no o nunca pueden parecer irrelevantes en un análisis univariado, pero son
esenciales para entender el sentimiento negativo cuando se combinan con otros términos.
Por último, el análisis comparativo integra perspectivas estadísticas (pruebas de hipótesis sobre
diferencias en precisión y exactitud), computacionales (complejidad de algoritmos) y
geométricas (proyecciones en espacios reducidos), ofreciendo una visión más amplia del
problema de selección de características en sistemas de reconocimiento de patrones.
4. Desarrollo
Ejercicio: Selección de Características con el Conjunto de datos Wine.
1. Utilizar el conjunto de datos Wine (UCI Machine Learning Repository): Este conjunto
de datos multidimensional describe propiedades químicas de tres variedades de vinos y cuenta
con 178 muestras, 13 características químicas. Este conjunto de datos presenta un escenario
ideal para explorar técnicas de reducción dimensional, ya que combina atributos correlacionados
(como concentraciones de fenoles y flavonoides) con características potencialmente
discriminatorias (como el color o la alcalinidad).
a) Verificar la integridad del conjunto de datos (valores faltantes, rangos válidos).
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
2
IIMAS, UNAM
Fabián Sandoval
Reconocimiento de Patrones
—------------------------------------------------------------------------------------------------------------------------
Para esta parte utilice la función ismissing() que en conjunto con la función sum devolverá el
total de valores faltantes por columna del dataset. La salida que obtuve fue la siguiente:
Posteriormente para ver el rango de valores válidos permitidos así como su tipo de dato para
cada columna utilice la función summary() que devuelve eso además de algunas otras estadísticas
descriptivas. La salida que obtuve fue la siguiente:
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
3
IIMAS, UNAM
Fabián Sandoval
Reconocimiento de Patrones
—------------------------------------------------------------------------------------------------------------------------
2. Preparación de Datos:
a) Cargar el dataset y dividirlo en 70 % entrenamiento / 30 % prueba.
En primer lugar cargue el conjunto de datos con la función readtable(), después se tiene que
definir los vectores de características que en realidad son todas las columnas del dataset pero sin
las etiquetas. Así se vería la impresión de los primeros registros:
Posteriormente cargamos el vector de salida o de etiquetas, así sería la impresión de los primeros
registros:
b) Normalizar los datos (z-score).
Posteriormente realizamos una normalización al vector X de características la cual normaliza los
datos utilizando la estandarización z-score, que consiste en convertir los datos para que tengan
media 0 y desviación estándar 1. Esto se hace variable por variable (columna por columna) en la
matriz de datos.
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
4
IIMAS, UNAM
Fabián Sandoval
Reconocimiento de Patrones
—------------------------------------------------------------------------------------------------------------------------
c) Crear un clasificador base (KNN con k = 3 vecinos).
Después dividimos estos dos vectores en su conjunto de entrenamiento y de prueba con una
proporción de 70%/30% respectivamente. Adicionalmente definimos el número de
características a seleccionar igual a 5 como un parámetro común para posteriores métodos,
además de un clasificador K-NN que predecirá las etiquetas del conjunto de prueba con base en
los tres vecinos más cercanos.
3. Implementación de Métodos:
a) Búsqueda Exhaustiva
Este método consiste en generar todas las combinaciones posibles de 5 características entre las 13
disponibles y evaluar una muestra aleatoria de hasta 1000 combinaciones, para reducir el tiempo
de cómputo. Para cada subconjunto, se entrena un clasificador k-NN (con 3 vecinos) usando
solo esas características, y se calcula la exactitud sobre un conjunto de prueba previamente
separado. Al finalizar, se selecciona el subconjunto que produjo la mayor precisión como el
mejor conjunto de 5 características para el modelo.
● Modificar código para seleccionar 5 características.
Después de hacer los cambios correspondientes la salida fue la siguiente:
● Analizar resultados.
Al utilizar K-NN con estas características se obtuvo la siguiente exactitud:
Obtener una exactitud del 100% con este método significa que el clasificador predijo
correctamente todas las etiquetas del conjunto de prueba usando ese subconjunto específico de 5
características. Es decir, no cometió ningún error en esa evaluación.
b) Búsqueda Secuencial hacia delante (SFS)
● Ejecutar con validación cruzada 5-fold.
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
5
IIMAS, UNAM
Fabián Sandoval
Reconocimiento de Patrones
—------------------------------------------------------------------------------------------------------------------------
Para ello simplemente se ejecuta el código de este método proporcionado por el profesor,
el cual consiste en encontrar un subconjunto óptimo de variables que maximicen el
rendimiento del clasificador k-NN.
Primero, se configura una validación cruzada de 5 particiones (kfold=5) sobre los datos
de entrenamiento para evaluar cada subconjunto de características de forma más
robusta. Luego, mediante la función sequentialfs, se inicia la búsqueda añadiendo
características una por una. En cada paso, se elige la característica que, al ser añadida al
conjunto actual, produce el mayor aumento (o menor error) en el rendimiento del
clasificador. La métrica de evaluación usada es el número de errores de clasificación, y se
busca minimizar.
El proceso se detiene cuando se han seleccionado k = 5 características. Finalmente, se
muestra el conjunto seleccionado y se calcula la exactitud del modelo resultante al
aplicarlo sobre el conjunto de prueba, usando solo esas 5 características seleccionadas.
Este método es más eficiente y menos propenso al sobreajuste que una búsqueda
exhaustiva, ya que considera un número mucho menor de combinaciones y utiliza
validación cruzada para guiar la selección.
La salida obtenida fue la siguiente, como podemos ver las características seleccionadas
fueron [6,7,10,12,13] y se obtuvo una exactitud del 94.34% :
● Generar gráfico de exactitud por características:
La gráfica representa cómo cambia el error de validación cruzada a medida que se
agregan características en el proceso de selección secuencial hacia adelante
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
6
IIMAS, UNAM
Fabián Sandoval
Reconocimiento de Patrones
—------------------------------------------------------------------------------------------------------------------------
c) Fisher
● Implementar función del cálculo de Score de separabilidad entre clases.
Este código implementa un proceso de selección de características basado en el método
Fisher Score, que evalúa individualmente cada variable del conjunto de datos para medir
qué tan bien separa las clases del problema de clasificación. La idea es identificar aquellas
características que maximizan la separación entre clases mientras minimizan la variación
interna dentro de cada clase.
La función fisher_score toma como entrada una única característica (es decir, una
columna del conjunto de entrenamiento) y las etiquetas de clase correspondientes.
Dentro de esta función, se calculan dos cantidades clave: la varianza entre clases
(between) y la varianza dentro de cada clase (within). Para cada clase, se identifica cuántos
ejemplos pertenecen a ella, se calcula su media y varianza, y se acumulan estos valores
según su contribución a la separación entre clases o a la dispersión interna. El Fisher
Score final se obtiene dividiendo la varianza entre clases por la varianza interna. Cuanto
mayor sea este cociente, más útil es esa característica para distinguir entre clases.
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
7
IIMAS, UNAM
Fabián Sandoval
Reconocimiento de Patrones
—------------------------------------------------------------------------------------------------------------------------
En la segunda parte del código, se aplica esta función a cada una de las 13 características
del conjunto de entrenamiento. El resultado es un vector que contiene el Fisher Score de
cada característica. Luego, se ordenan estos puntajes de mayor a menor y se seleccionan
las k características más relevantes según este criterio. Esta selección se basa únicamente
en la capacidad de cada variable de manera individual, sin considerar combinaciones
entre ellas.
(El código de la función implementada está en la sección de código)
● Seleccionar las 5 características con mayor puntuación.
Estas son las 5 características seleccionadas según fisher_score:
Finalmente, se entrena un clasificador utilizando únicamente las características
seleccionadas y se evalúa su desempeño sobre el conjunto de prueba. Se calcula la
exactitud como el porcentaje de predicciones correctas, y se imprimen tanto las
características seleccionadas como la exactitud final del modelo.
d) Rama y Límite (B&B)
Este método utiliza la técnica de Rama y Límite (Branch & Bound) para seleccionar el mejor
subconjunto de características (en este caso, 5 de 13) basado en sus Fisher Scores, que miden la
capacidad de cada característica para discriminar entre clases.
Primero, se calculan los Fisher Scores de todas las características. Luego, se define un límite
superior (upper bound) para cada subconjunto parcial, estimando la mejor puntuación que se
podría alcanzar si se completara ese subconjunto con las mejores características restantes. Esta
estimación permite poda de ramas: si el upper bound de un subconjunto parcial no supera la
mejor puntuación encontrada hasta el momento, no se continúa explorando esa rama, ya que no
puede conducir a una solución mejor.
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
8
IIMAS, UNAM
Fabián Sandoval
Reconocimiento de Patrones
—------------------------------------------------------------------------------------------------------------------------
El algoritmo recorre recursivamente el espacio de búsqueda, construyendo subconjuntos y
evaluando si vale la pena seguir explorando o no. Cuando encuentra un subconjunto completo
de 5 características, evalúa su puntuación total y actualiza el mejor subconjunto global si es
superior al anterior.
Finalmente, se entrena un clasificador usando sólo las características seleccionadas y se calcula la
exactitud del modelo. Este enfoque es más inteligente que la búsqueda exhaustiva, ya que evita
explorar combinaciones que no tienen potencial, pero sigue siendo exacto, ya que garantiza
encontrar el mejor subconjunto posible (dado el criterio de puntuación).
● Comparar con SFS.
A continuación presento un cuadro comparativo que realice entre SFS y Branch &
Bound:
● Analizar resultados.
Los resultados obtenidos son los siguientes:
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
9
IIMAS, UNAM
Fabián Sandoval
Reconocimiento de Patrones
—------------------------------------------------------------------------------------------------------------------------
e) PCA
El Análisis de Componentes Principales (PCA) es una técnica de reducción de dimensionalidad
que transforma las características originales en un nuevo conjunto de variables llamadas
componentes principales, que son combinaciones lineales de las variables originales. Estos
componentes están ordenados según la cantidad de varianza que explican en los datos.
En este método, se aplica PCA sobre el conjunto de entrenamiento para obtener:
- Las componentes principales (coeff)
- La proyección de los datos (score)
- El porcentaje de varianza explicada por cada componente (explained)
Luego, se selecciona el número mínimo de componentes necesarios para explicar al menos el
95% de la varianza total de los datos (aunque se garantizan al menos dos componentes para
propósitos de visualización si fuera necesario).
Los datos de entrenamiento y prueba se proyectan sobre estas componentes seleccionadas, y se
entrena un clasificador sobre esta versión reducida de los datos. Finalmente, se evalúa la
exactitud del modelo.
Este enfoque no selecciona características originales, sino que crea nuevas características que
maximizan la varianza y, por lo tanto, puede resultar en mejores resultados en presencia de datos
ruidosos o altamente correlacionados. A diferencia de los otros métodos que seleccionan un
subconjunto de características originales, PCA transforma el espacio de entrada, lo cual puede
dificultar la interpretación directa de las variables seleccionadas.
● Determinar componentes para 95 % de varianza.
El resultado fue el siguiente:
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
10
IIMAS,
UNAM
Fabián Sandoval
Reconocimiento de Patrones
—------------------------------------------------------------------------------------------------------------------------
● Visualizar proyección 2D.
Adicionalmente hice esta visualización opcional:
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
11
IIMAS,
UNAM
Fabián Sandoval
Reconocimiento de Patrones
—------------------------------------------------------------------------------------------------------------------------
4. Análisis Comparativo:
a) Crear tabla comparativa con:
● Método
● Características seleccionadas
● Métricas de entrenamiento y prueba
● Comentar los mejores resultados
Los resultados obtenidos muestran un alto rendimiento en todos los métodos de selección de
características, con exactitudes superiores al 94% en el conjunto de prueba. Los métodos
Exhaustivo, Fisher, Rama y Límite alcanzaron el máximo rendimiento (96.2%), seguidos muy de
cerca por PCA con igual exactitud en prueba aunque con menor exactitud en entrenamiento.
Solo SFS mostró un rendimiento ligeramente inferior (94.3%).
Las características más relevantes fueron consistentemente:
- Flavanoids (7): Compuestos fenólicos importantes en vinos
- Proline (13): Aminoácido clave en la calidad del vino
- Color_Intensity (10): Intensidad del color
- OD280 (12): Medida de concentración de proteínas
5. Análisis de resultados :
Hice esta gráfica para complementar el análisis de los resultados:
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
12
IIMAS,
UNAM
Fabián Sandoval
Reconocimiento de Patrones
—------------------------------------------------------------------------------------------------------------------------
a) ¿Qué método obtuvo mejor exactitud? ¿Por qué?
Tres métodos compartieron la mejor exactitud (96.2%): Búsqueda Exhaustiva, Fisher Score y
Rama y Límite. Este excelente rendimiento se debe principalmente a que todos identificaron
correctamente el mismo conjunto de características químicas fundamentales que diferencian las
variedades de vino. Particularmente, la inclusión consistente de Flavanoids y Proline -dos de los
marcadores químicos más importantes en enología- fue determinante para la alta precisión.
b) ¿Cómo afecta la correlación entre características al PCA?
El análisis PCA requirió 10 componentes principales para capturar la varianza suficiente,
indicando una correlación moderada entre las características originales. El hecho que PCA
igualara en rendimiento a los mejores métodos selectores sugiere que las direcciones de máxima
varianza en los datos coincidieron con las direcciones más discriminativas para clasificar los
vinos. Esto es particularmente valioso porque PCA, al ser un método no supervisado, logró este
rendimiento sin usar información sobre las clases.
c) ¿Qué ventajas tiene Fisher Score sobre SFS en términos computacionales?
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
13
IIMAS,
UNAM
Fabián Sandoval
Reconocimiento de Patrones
—------------------------------------------------------------------------------------------------------------------------
Fisher Score demostró ser superior a SFS tanto en rendimiento (96.2% vs 94.3%) como en
eficiencia computacional. Esta ventaja se debe a que Fisher evalúa características
individualmente mediante cálculos estadísticos simples O(n), mientras que SFS requiere
múltiples evaluaciones de modelos con validación cruzada O(n²). Además, Fisher permite
paralelización trivial al calcular scores independientemente, a diferencia de SFS que es
inherentemente secuencial. La efectividad de Fisher en este caso particular sugiere que las
características más discriminativas (Flavanoids, Proline) son buenos predictores individuales.
5. Código
% Leer el archivo CSV
data = readtable('Wine.csv');
% Mostrar las primeras filas
disp('Primeras filas del dataset:');
disp(head(data));
% Verificar valores faltantes (NaN)
disp('Número de valores faltantes por columna:');
missing = sum(ismissing(data));
disp(missing);
% Estadísticas descriptivas para verificar rangos
disp('Estadísticas descriptivas:');
summary(data);
%% Carga y preprocesamiento de datos
clear; close all; clc;
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
14
IIMAS,
UNAM
Fabián Sandoval
Reconocimiento de Patrones
—-----------------------------------------------------------------------------------------------------------------------% Cargar conjunto de datos Wine (13 características, 3 clases)
% load wine.data
%load('wineData.mat');
wine = readtable('Wine.csv');
X = wine{:, 1:13};
% Características
Y = wine{:, 14};
% Etiquetas
disp(X);
disp(Y);
% Normalización z-score
X = zscore(X);
% Dividir en entrenamiento (70%) y prueba (30%)
rng(1);
% Para reproducibilidad
cv = cvpartition(Y, 'HoldOut', 0.3);
X_train = X(cv.training,:);
Y_train = Y(cv.training);
X_test = X(cv.test,:);
Y_test = Y(cv.test);
%% Parámetros comunes
k = 5;
% Número de características a seleccionar
classifier = @(XTRAIN, YTRAIN, XTEST) predict(fitcknn(XTRAIN, YTRAIN,
'NumNeighbors',3), XTEST);
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
15
IIMAS,
UNAM
Fabián Sandoval
Reconocimiento de Patrones
—-----------------------------------------------------------------------------------------------------------------------%% 1. Búsqueda Exhaustiva (modificado para 5 características)
fprintf('--- Búsqueda Exhaustiva (5 características) ---\n');
n_features = 5;
comb = nchoosek(1:13, n_features);
best_acc = 0;
best_subset = [];
% Limitar el número de combinaciones para evitar tiempo computacional
excesivo
max_comb = min(1000, size(comb,1)); % Evaluar máximo 1000
combinaciones
rng(1); % Para reproducibilidad
selected_comb = randperm(size(comb,1), max_comb);
for i = selected_comb
acc = sum(classifier(X_train(:,comb(i,:)), Y_train,
X_test(:,comb(i,:))) == Y_test)/numel(Y_test);
if acc > best_acc
best_acc = acc;
best_subset = comb(i,:);
end
end
fprintf('Mejor subconjunto (5 características): %s\n',
mat2str(best_subset));
fprintf('Exactitud: %.2f%%\n\n', best_acc*100);
%% 2. Búsqueda Secuencial Forward
fprintf('--- Búsqueda Secuencial Forward ---\n');
opts = statset('Display','iter', 'UseParallel',true);
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
16
IIMAS,
UNAM
Fabián Sandoval
Reconocimiento de Patrones
—-----------------------------------------------------------------------------------------------------------------------c = cvpartition(Y_train, 'kfold',5);
[fs_sfs, history] = sequentialfs(@(XTRAIN, YTRAIN, XTEST, YTEST) ...
sum(classifier(XTRAIN, YTRAIN, XTEST) ~= YTEST), ...
X_train, Y_train, 'cv',c, 'options',opts, 'nfeatures',k);
fprintf('Características seleccionadas: %s\n',
mat2str(find(fs_sfs)));
acc = sum(classifier(X_train(:,fs_sfs), Y_train, X_test(:,fs_sfs)) ==
Y_test)/numel(Y_test);
fprintf('Exactitud: %.2f%%\n\n', acc*100);
% Gráfico de exactitud por número de características
figure;
plot(1:k, history.Crit(end-k+1:end), 'o-');
xlabel('Número de características');
ylabel('Error de validación cruzada');
title('Búsqueda Secuencial Forward');
grid on;
%% Función Fisher Score
function score = fisher_score(feature, labels)
classes = unique(labels);
n_classes = length(classes);
overall_mean = mean(feature);
between = 0;
within = 0;
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
17
IIMAS,
UNAM
Fabián Sandoval
Reconocimiento de Patrones
—-----------------------------------------------------------------------------------------------------------------------for i = 1:n_classes
idx = (labels == classes(i));
n_i = sum(idx);
mean_i = mean(feature(idx));
var_i = var(feature(idx),1);
between = between + n_i*(mean_i - overall_mean)^2;
within = within + n_i*var_i;
end
score = between / within;
end
%% 3. Fisher Score
fprintf('--- Fisher Score ---\n');
fisher_scores = zeros(1,13);
for i = 1:13
fisher_scores (i) = fisher_score(X_train(:,i), Y_train);
end
[~, fisher_idx] = sort(fisher_scores, 'descend');
selected_fisher = fisher_idx(1:k);
fprintf('Características seleccionadas: %s\n',
mat2str(selected_fisher));
acc = sum(classifier(X_train(:,selected_fisher), Y_train,
X_test(:,selected_fisher)) == Y_test)/numel(Y_test);
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
18
IIMAS,
UNAM
Fabián Sandoval
Reconocimiento de Patrones
—-----------------------------------------------------------------------------------------------------------------------fprintf('Exactitud: %.2f%%\n\n', acc*100);
%% 4. Rama y Límite (Branch & Bound) - Versión corregida y probada
fprintf('--- Rama y Límite ---\n');
% 1. Precalcular Fisher Scores para todas las características
fisher_scores = zeros(1, 13);
for i = 1:13
fisher_scores(i) = fisher_score(X_train(:, i), Y_train);
end
% 2. Configuración inicial
k = 5; % Número de características a seleccionar
n_features = 13; % Total de características
best_subset = [];
best_score = -inf;
% 3. Función auxiliar para calcular el upper bound
calculate_upper_bound = @(current_set, current_score, start_idx) ...
current_score + sum(maxk(fisher_scores(start_idx:end), k length(current_set)));
% 4. Llamada inicial al algoritmo
best_subset = branch_and_bound_corrected(1, [], fisher_scores, k,
n_features, calculate_upper_bound);
% 5. Verificar que se encontró un subconjunto válido
if isempty(best_subset)
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
19
IIMAS,
UNAM
Fabián Sandoval
Reconocimiento de Patrones
—-----------------------------------------------------------------------------------------------------------------------error('No se encontró un subconjunto válido. Revisar los
parámetros o el algoritmo.');
else
fprintf('Mejor subconjunto (5 características): %s\n',
mat2str(best_subset));
acc = sum(classifier(X_train(:, best_subset), Y_train, X_test(:,
best_subset)) == Y_test) / numel(Y_test);
fprintf('Exactitud: %.2f%%\n\n', acc * 100);
end
%% Función principal de Branch & Bound corregida
function best_subset = branch_and_bound_corrected(start, current_set,
fisher_scores, k, n_features, ub_fn)
persistent global_best_set;
persistent global_best_score;
% Inicializar variables persistentes
if isempty(global_best_set)
global_best_set = [];
global_best_score = -inf;
end
% Caso base: tenemos un subconjunto completo
if length(current_set) == k
current_score = sum(fisher_scores(current_set));
if current_score > global_best_score
global_best_score = current_score;
global_best_set = current_set;
end
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
20
IIMAS,
UNAM
Fabián Sandoval
Reconocimiento de Patrones
—-----------------------------------------------------------------------------------------------------------------------return;
end
% Explorar ramas
for i = start:n_features
new_set = [current_set, i];
remaining = k - length(new_set);
% Solo continuar si es posible completar el subconjunto
if (n_features - i) >= remaining
current_score = sum(fisher_scores(new_set));
upper_bound = ub_fn(new_set, current_score, i+1);
% Podar ramas no prometedoras
if upper_bound > global_best_score
branch_and_bound_corrected(i+1, new_set,
fisher_scores, k, n_features, ub_fn);
end
end
end
% Devolver el mejor subconjunto encontrado
best_subset = global_best_set;
end
%% 5. Análisis de Componentes Principales (PCA) - Versión corregida
fprintf('--- PCA ---\n');
[coeff, score, ~, ~, explained] = pca(X_train);
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
21
IIMAS,
UNAM
Fabián Sandoval
Reconocimiento de Patrones
—-----------------------------------------------------------------------------------------------------------------------% Opción 1: Usar 2 componentes fijos para visualización
n_components_visual = 2;
% Opción 2: Componentes para 95% varianza (pero mínimo 2 para
visualización)
n_components = max(find(cumsum(explained) >= 95, 1), 2);
% Proyección para clasificación (puede usar más componentes)
n_components_class = find(cumsum(explained) >= 95, 1);
fprintf('Varianza explicada por componentes:\n');
disp(cumsum(explained(1:5)')); % Mostrar varianza acumulada de
primeros 5 componentes
fprintf('Componentes seleccionados para clasificación: %d (%.2f%%
varianza)\n', ...
n_components_class, cumsum(explained(n_components_class)));
X_train_pca = X_train * coeff(:,1:n_components_class);
X_test_pca = X_test * coeff(:,1:n_components_class);
acc = sum(classifier(X_train_pca, Y_train, X_test_pca) ==
Y_test)/numel(Y_test);
fprintf('Exactitud: %.2f%%\n\n', acc*100);
%% 6. Análisis Comparativo - Versión compatible con .mlx
fprintf('--- Análisis Comparativo ---\n');
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
22
IIMAS,
UNAM
Fabián Sandoval
Reconocimiento de Patrones
—-----------------------------------------------------------------------------------------------------------------------% Asegurarse que todas las variables necesarias existen
if ~exist('best_subset', 'var') || isempty(best_subset)
best_subset = []; % Valor por defecto si no existe
end
if ~exist('fs_sfs', 'var')
fs_sfs = false(1,13); % Valor por defecto
end
if ~exist('selected_fisher', 'var')
selected_fisher = []; % Valor por defecto
end
if ~exist('best_subset_bb', 'var')
% Intentar obtener los resultados de Branch & Bound de otra manera
try
% Aquí puedes incluir el código alternativo para obtener
best_subset_bb
% Por ejemplo, podrías usar los mismos resultados de Fisher si
Branch & Bound falló
best_subset_bb = selected_fisher;
warning('Usando resultados de Fisher como fallback para Branch
& Bound');
catch
best_subset_bb = 1:5; % Valor por defecto (primeras 5
características)
warning('Usando primeras 5 características como fallback para
Branch & Bound');
end
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
23
IIMAS,
UNAM
Fabián Sandoval
Reconocimiento de Patrones
—-----------------------------------------------------------------------------------------------------------------------end
if ~exist('n_components', 'var')
n_components = 2; % Valor por defecto
end
% Crear la tabla comparativa
methods = {'Exhaustiva'; 'SFS'; 'Fisher'; 'Rama y Límite'; 'PCA'};
features_selected = {
mat2str(best_subset);
mat2str(find(fs_sfs));
mat2str(selected_fisher);
mat2str(best_subset_bb);
sprintf('%d componentes', n_components)
};
% Calcular exactitudes
train_acc = zeros(5,1);
test_acc = zeros(5,1);
% 1. Exhaustiva
if ~isempty(best_subset)
train_acc(1) = sum(classifier(X_train(:,best_subset), Y_train,
X_train(:,best_subset)) == Y_train)/numel(Y_train);
test_acc(1) = sum(classifier(X_train(:,best_subset), Y_train,
X_test(:,best_subset)) == Y_test)/numel(Y_test);
end
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
24
IIMAS,
UNAM
Fabián Sandoval
Reconocimiento de Patrones
—-----------------------------------------------------------------------------------------------------------------------% 2. SFS
train_acc(2) = sum(classifier(X_train(:,fs_sfs), Y_train,
X_train(:,fs_sfs)) == Y_train)/numel(Y_train);
test_acc(2) = sum(classifier(X_train(:,fs_sfs), Y_train,
X_test(:,fs_sfs)) == Y_test)/numel(Y_test);
% 3. Fisher
train_acc(3) = sum(classifier(X_train(:,selected_fisher), Y_train,
X_train(:,selected_fisher)) == Y_train)/numel(Y_train);
test_acc(3) = sum(classifier(X_train(:,selected_fisher), Y_train,
X_test(:,selected_fisher)) == Y_test)/numel(Y_test);
% 4. Branch & Bound
train_acc(4) = sum(classifier(X_train(:,best_subset_bb), Y_train,
X_train(:,best_subset_bb)) == Y_train)/numel(Y_train);
test_acc(4) = sum(classifier(X_train(:,best_subset_bb), Y_train,
X_test(:,best_subset_bb)) == Y_test)/numel(Y_test);
% 5. PCA
if exist('X_train_pca', 'var') && exist('X_test_pca', 'var')
train_acc(5) = sum(classifier(X_train_pca, Y_train, X_train_pca)
== Y_train)/numel(Y_train);
test_acc(5) = sum(classifier(X_train_pca, Y_train, X_test_pca) ==
Y_test)/numel(Y_test);
else
% Calcular PCA si no existe
[coeff, ~, ~, ~, explained] = pca(X_train);
n_comp = max(find(cumsum(explained) >= 95, 1), 2);
X_train_pca = X_train * coeff(:,1:n_comp);
X_test_pca = X_test * coeff(:,1:n_comp);
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
25
IIMAS,
UNAM
Fabián Sandoval
Reconocimiento de Patrones
—-----------------------------------------------------------------------------------------------------------------------train_acc(5) = sum(classifier(X_train_pca, Y_train, X_train_pca)
== Y_train)/numel(Y_train);
test_acc(5) = sum(classifier(X_train_pca, Y_train, X_test_pca) ==
Y_test)/numel(Y_test);
end
% Crear tabla
T = table(methods, features_selected, train_acc, test_acc, ...
'VariableNames', {'Método', 'Características_Seleccionadas',
'Exactitud_Entrenamiento', 'Exactitud_Prueba'});
disp(T);
% Gráfico comparativo
figure;
bar([train_acc, test_acc]);
set(gca, 'XTickLabel', methods);
ylabel('Exactitud');
legend('Entrenamiento', 'Prueba', 'Location', 'best');
title('Comparación de Métodos de Selección de Características');
grid on;
% Mostrar mejores resultados
[best_test_acc, idx] = max(test_acc);
fprintf('\nMejor método: %s con %.2f%% de exactitud en prueba\n', ...
methods{idx}, best_test_acc*100);
% ACÁ BAJO PUSE LAS VISUALIZACIONES DE PCA
% Visualización proyección 2D (siempre con 2 componentes)
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
26
IIMAS,
UNAM
Fabián Sandoval
Reconocimiento de Patrones
—-----------------------------------------------------------------------------------------------------------------------figure;
gscatter(score(:,1), score(:,2), Y_train);
xlabel(sprintf('PC1 (%.1f%% varianza)', explained(1)));
ylabel(sprintf('PC2 (%.1f%% varianza)', explained(2)));
title('Proyección PCA 2D');
grid on;
% Opcional: Gráfico de varianza explicada
figure;
pareto(explained);
xlabel('Componentes Principales');
ylabel('Varianza Explicada (%)');
title('Varianza explicada por cada componente');
grid on;
6. Conclusiones
La realización de esta práctica ha representado una experiencia sumamente enriquecedora en mi
formación como científico de datos. A lo largo de este trabajo, no solo consolidé mis
conocimientos sobre técnicas de selección de características, sino que también descubrí la
importancia fundamental que tiene este proceso en el desarrollo de modelos de machine
learning eficientes y robustos.
El trabajar directamente con el conjunto de datos de vinos me permitió comprender en
profundidad cómo las propiedades químicas de estos productos pueden ser analizadas y
transformadas en características discriminativas. Resulta fascinante cómo a través de métodos
matemáticos y estadísticos podemos identificar qué compuestos específicos (como los
flavonoides o el aminoácido prolina) son verdaderamente determinantes para diferenciar entre
variedades de vino. Este conocimiento no solo tiene valor académico, sino también aplicaciones
prácticas en la industria vitivinícola.
Uno de los aspectos más reveladores fue comparar los distintos métodos de selección.
Particularmente, me sorprendió comprobar cómo Fisher Score, siendo uno de los métodos más
simples conceptualmente, logró igualar el rendimiento de técnicas más complejas como la
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
27
IIMAS,
UNAM
Fabián Sandoval
Reconocimiento de Patrones
—------------------------------------------------------------------------------------------------------------------------
Búsqueda Exhaustiva o Rama y Límite, alcanzando una excelente precisión del 96.2%. Esto
demuestra que en problemas bien estructurados, soluciones elegantes y computacionalmente
eficientes pueden ser igual de efectivas que aproximaciones más sofisticadas.
El caso del PCA fue especialmente ilustrativo, mostrándonos cómo un método no supervisado
puede, en ciertos contextos, lograr resultados comparables a técnicas supervisadas cuando existe
una alineación entre la varianza de los datos y su capacidad discriminativa. Esta observación
refuerza la importancia de comprender la naturaleza de nuestros datos antes de seleccionar
cualquier técnica de reducción dimensional.
Más allá de los resultados numéricos, lo más valioso de esta práctica ha sido desarrollar la
capacidad de analizar críticamente el rendimiento de diferentes algoritmos, entendiendo no solo
su efectividad sino también sus limitaciones computacionales y teóricas. Como científicos de
datos, debemos ser capaces de tomar decisiones fundamentadas sobre qué métodos emplear
según las particularidades de cada problema y los recursos disponibles.
Finalmente, esta experiencia ha reafirmado mi entusiasmo por el campo del machine learning y
el análisis de datos. Los excelentes resultados obtenidos (con precisiones cercanas al 96% en
varios métodos) son motivadores, pero más importante aún es haber comprendido el proceso
que lleva a esos resultados. Estoy convencido de que las habilidades desarrolladas en esta práctica
serán fundamentales en mi carrera profesional, y me generan gran expectativa por enfrentar
nuevos desafíos en el fascinante mundo de la ciencia de datos, donde cada conjunto de datos
representa un nuevo universo por explorar y comprender.
7. Referencias
■ Gonzalez, R., Woods, R., Digital Image Processing, Prentice Hall,
2008.
■ Pratt, W. k., Digital Image Processing, John Wiley and Sons Inc,
2001.
■ Jahne, B., Digital Image Processing, Springer, 2005.
■ Sánchez Garreta, Josep Salvador; García, Vicente. Special Issue on
Data Preprocessing in Pattern Recognition: Recent Progress, Trends
and Applications. 2022.
———-----------------------------------------------------------------------------------------------------------------Ph. D. Elena Martínez
28
IIMAS,
UNAM
0
Puede agregar este documento a su colección de estudio (s)
Iniciar sesión Disponible sólo para usuarios autorizadosPuede agregar este documento a su lista guardada
Iniciar sesión Disponible sólo para usuarios autorizados(Para quejas, use otra forma )