/*
* @fileoverview Clase para realizar clasificación utilizando el algoritmo Naive Bayes.
*
* Generado como parte del proyecto CAIM+BAYES+CV K-FOLDS.
*
* Basado en:
* NBcClasser.php
* Tarea 4. Aprendizaje y clasificación de documentos
* Métodos Probabilísticos para la Inteligencia Artificial
*
* @author Fernando MM
* @version 1.0
* @date 2024-04-11
*
* Dependencias:
* - arffDataSet.js
* - caimDiscretizer.js
*
* Historial de cambios:
* - 1.0 (2024-04-11): Creación de la librería.
*
*/
/**
* @class La clase NaiveBayes crea un modelo de predicción usando las probilidades del teorema de Bayes tradicional.
*/
class NaiveBayes {
constructor() {
/**
* @type {Array}
*/
this.classProbabilities = {}; // Almacena las probabilidades de cada clase.
/**
* @type {Array}
*/
this.featureProbabilities = {}; // Almacenar las probabilidades de cada característica dada una clase.
}
/**
* @description Regresa el nombre del modelo usado.
* @returns {string}
*/
getClassifierName(){
return "Naive Bayes";
}
/**
* @description Entrena el modelo con un conjunto de datos de características (X) y etiquetas de clase (y).
* @param {Array} X X representa las características de las instancias.
* @param {Array} y y representa las etiquetas de clase correspondientes.
*/
train(X, y) {
// Separar las instancias de entrenamiento por clase para calcular las probabilidades.
const separated = y.reduce((acc, classValue, index) => {
// Si no existe un arreglo para la clase actual, crearlo.
if (!acc[classValue]) {
acc[classValue] = [];
}
// Agregar la instancia actual al arreglo de la clase correspondiente.
acc[classValue].push(X[index]);
return acc;
}, {});
// Calcular la probabilidad de cada clase y la probabilidad de cada característica dado una clase.
Object.keys(separated).forEach((classValue) => {
// Probabilidad de la clase = número de instancias de la clase / número total de instancias.
this.classProbabilities[classValue] = separated[classValue].length / y.length;
// Reducir las instancias de cada clase para calcular la frecuencia absoluta de cada característica.
this.featureProbabilities[classValue] = separated[classValue].reduce((acc, instance) => {
instance.forEach((value, featureIndex) => {
if (!acc[featureIndex]) {
acc[featureIndex] = {};
}
if (!acc[featureIndex][value]) {
acc[featureIndex][value] = 1;
} else {
acc[featureIndex][value] += 1;
}
});
return acc;
}, {});
// Convertir conteos a probabilidades para cada característica.
Object.keys(this.featureProbabilities[classValue]).forEach((featureIndex) => {
const total = Object.values(this.featureProbabilities[classValue][featureIndex]).reduce((sum, count) => sum + count, 0);
Object.keys(this.featureProbabilities[classValue][featureIndex]).forEach((value) => {
this.featureProbabilities[classValue][featureIndex][value] /= total;
});
});
});
}
/**
* @description Predice las clases de un nuevo conjunto de datos de características (X).
* @param {Array} X Datos para predicción.
* @returns {Array}
*/
predict(X) {
return X.map((instance) => this.predictInstance(instance));
}
/**
* @description Método auxiliar para predecir la clase de una única instancia.
* @param {Array} instance Datos para predicción.
* @returns {Array}
*/
predictInstance(instance) {
const probabilities = Object.keys(this.classProbabilities).reduce((acc, classValue) => {
let probability = this.classProbabilities[classValue];
instance.forEach((value, featureIndex) => {
if (this.featureProbabilities[classValue][featureIndex] && this.featureProbabilities[classValue][featureIndex][value]) {
probability *= this.featureProbabilities[classValue][featureIndex][value];
} else {
// Manejar caso en que el valor de la característica no se haya visto durante el entrenamiento
probability *= 1e-6; // Pequeño valor para evitar multiplicar por cero
}
});
acc[classValue] = probability;
return acc;
}, {});
// Seleccionar la clase con la mayor probabilidad acumulada.
return Object.keys(probabilities).reduce((acc, classValue) => {
return probabilities[classValue] > probabilities[acc] ? classValue : acc;
});
}
}
/* EJEMPLO EN JAVASCRIPT
const nb = new NaiveBayes();
// X representa las características de las instancias
const X = [
[1, 1],
[1, 0],
[0, 1],
[0, 0]
];
// y representa las etiquetas de clase correspondientes
const y = [
'yes',
'yes',
'no',
'no'
];
// Entrenar el modelo con los datos proporcionados
nb.train(X, y);
// Ejemplo de datos para predicción:
const newInstances = [
[1, 1],
[0, 0]
];
// Realizar predicciones
const predictions = nb.predict(newInstances);
console.log("Predicciones:", predictions);
*/