Previous Next

8.4 Anexo 4. Algoritmo Naive Bayes

 

 

public class NaiveBayes extends DistributionClassifier

implements OptionHandler, WeightedInstancesHandler {

/** Los estimadores de atributo. */

protected Estimator [][] m_Distributions;

 

/** El estimados de la clase. */

protected Estimator m_ClassDistribution;

/**

* Usar el estimador del kernel en vez de la Normal

*/

protected boolean m_UseKernelEstimator;

/** La cantidad de clases (o 1 si es numerica) */

protected int m_NumClasses;

/** El encabezado para entregar el modelo

*/

protected Instances m_Instances;

/*** El parametro de precision para los atributos numericos */

protected static final double DEFAULT_NUM_PRECISION = 0.01;

/**

* Genera el clasificador

*

* @param instances Instancias producidas de datos de entrada

* @exception Exception Si el clasificador no es generado exitosamente

*/

public void buildClassifier(Instances instances) throws Exception {

if (instances.checkForStringAttributes()) {

throw new Exception("Atributos numericos solamente");

}

if (instances.classAttribute().isNumeric()) {

throw new Exception("Naive Bayes: Clase es numerica!");

}

m_NumClasses = instances.numClasses();

if (m_NumClasses < 0) {

throw new Exception ("Dataset no tiene atributos de clase");

}

// Copiar las instancias

m_Instances = new Instances(instances);

// Reserva espacio para las distribuciones

m_Distributions = new Estimator[m_Instances.numAttributes() - 1]

[m_Instances.numClasses()];

m_ClassDistribution = new DiscreteEstimator(m_Instances.numClasses(),

true);

int attIndex = 0;

Enumeration enum = m_Instances.enumerateAttributes();

while (enum.hasMoreElements()) {

Attribute attribute = (Attribute) enum.nextElement();

// Si el atributo es numerico, determina la distribucion

// Precision numerica para diferencia entre atributos adyacentes

double numPrecision = DEFAULT_NUM_PRECISION;

if (attribute.type() == Attribute.NUMERIC) {

m_Instances.sort(attribute);

if ((m_Instances.numInstances() > 0)

&& !m_Instances.instance(0).isMissing(attribute)) {

double lastVal = m_Instances.instance(0).value(attribute);

double currentVal, deltaSum = 0;

int distinct = 0;

for (int i = 1; i < m_Instances.numInstances(); i++) {

Instance currentInst = m_Instances.instance(i);

if (currentInst.isMissing(attribute)) {

break;

}

currentVal = currentInst.value(attribute);

if (currentVal != lastVal) {

deltaSum += currentVal - lastVal;

lastVal = currentVal;

distinct++;

}

}

if (distinct > 0) {

numPrecision = deltaSum / distinct;

}

}

}

for (int j = 0; j < m_Instances.numClasses(); j++) {

switch (attribute.type()) {

case Attribute.NUMERIC:

if (m_UseKernelEstimator) {

m_Distributions[attIndex][j] =

new KernelEstimator(numPrecision);

} else {

m_Distributions[attIndex][j] =

new NormalEstimator(numPrecision);

}

break;

case Attribute.NOMINAL:

m_Distributions[attIndex][j] =

new DiscreteEstimator(attribute.numValues(), true);

break;

default:

throw new Exception("Tipo desconocido");

}

}

attIndex++;

}

// Calcula conteo

double sum;

Enumeration enumInsts = m_Instances.enumerateInstances();

while (enumInsts.hasMoreElements()) {

Instance instance =

(Instance) enumInsts.nextElement();

if (!instance.classIsMissing()) {

Enumeration enumAtts = m_Instances.enumerateAttributes();

attIndex = 0;

while (enumAtts.hasMoreElements()) {

Attribute attribute = (Attribute) enumAtts.nextElement();

if (!instance.isMissing(attribute)) {

m_Distributions[attIndex][(int)instance.classValue()].

addValue(instance.value(attribute), instance.weight());

}

attIndex++;

}

m_ClassDistribution.addValue(instance.classValue(),

instance.weight());

}

}

// Reserva espacio

m_Instances = new Instances(m_Instances, 0);

}

/**

* Calcula las probabilidades de la instancia

*

* @param instance Instancia a ser clasificada

* @return predicted Distribucion probabilistica de la clase

* @exception Exception Por si hay problemas

*/

public double [] distributionForInstance(Instance instance)

throws Exception {

 

double [] probs = new double[m_NumClasses];

for (int j = 0; j < m_NumClasses; j++) {

probs[j] = m_ClassDistribution.getProbability(j);

}

Enumeration enumAtts = instance.enumerateAttributes();

int attIndex = 0;

while (enumAtts.hasMoreElements()) {

Attribute attribute = (Attribute) enumAtts.nextElement();

if (!instance.isMissing(attribute)) {

double temp, max = 0;

for (int j = 0; j < m_NumClasses; j++) {

temp = Math.max(1e-75, m_Distributions[attIndex][j].

getProbability(instance.value(attribute)));

probs[j] *= temp;

if (probs[j] > max) {

max = probs[j];

}

if (Double.isNaN(probs[j])) {

throw new Exception("NaN retornado del estimador del atributo "

+ attribute.name() + ":\n"

+ m_Distributions[attIndex][j].toString());

}

}

if ((max > 0) && (max < 1e-75)) { // Peligro de subflujo de probabilidades

for (int j = 0; j < m_NumClasses; j++) {

probs[j] *= 1e75;

}

}

}

attIndex++;

}

// Mostrar Probabilidades

Utils.normalize(probs);

return probs;

}

/**

* Retorna las opciones actuales

*

* @return Arreglo de opciones

*/

public String [] getOptions() {

String [] options = new String [1];

int current = 0;

if (m_UseKernelEstimator) {

options[current++] = "-K";

}

while (current < options.length) {

options[current++] = "";

}

return options;

}

/**

* Si se usa estimador del kernel

*

* @return Valor de m_UseKernelEstimatory.

*/

public boolean getUseKernelEstimator() {

 

return m_UseKernelEstimator;

}

/**

* Retorna enumeracion de opciones disponibles

*

* @return Retorna enumeracion de opciones disponibles

*/

public Enumeration listOptions() {

Vector newVector = new Vector(1);

newVector.addElement(

 

new Option("\tUsar estimador de la densidad del kernel en vez de la\n"

+"\tdistribucion normal para atributos numericos ",

"K", 0,"-K"));

return newVector.elements();

}

/**

* Main para probar la clase

*

* @param argv Las opciones

*/

public static void main(String [] argv) {

try {

System.out.println(Evaluation.evaluateModel(new NaiveBayes(), argv));

} catch (Exception e) {

e.printStackTrace();

System.err.println(e.getMessage());

}

}

/**

* Parsea opciones dadas<p>

*

* -K <br>

* Usar estimador de kernel<p>

*

* @param options Arreglo de opciones

* @exception Exception Si una opcion no es aceptada

*/

public void setOptions(String[] options) throws Exception {

 

m_UseKernelEstimator = Utils.getFlag('K', options);

Utils.checkForRemainingOptions(options);

}

/**

* Fija si se usa estimador del kernel

*

* @param v Valor a asignar a m_UseKernelEstimatory.

*/

public void setUseKernelEstimator(boolean v) {

 

m_UseKernelEstimator = v;

}

/**

* Retorna descripcion del clasificador

*

* @return Una descripcion del clasificador

*/

public String toString() {

 

StringBuffer text = new StringBuffer();

text.append("Clasificador Naive Bayes");

if (m_Instances == null) {

text.append(": No hay modelo aún");

} else {

try {

for (int i = 0; i < m_Distributions[0].length; i++) {

text.append("\n\nClase " + m_Instances.classAttribute().value(i) +

": Probabilidad a priori = " + Utils.

doubleToString(m_ClassDistribution.getProbability(i),

4, 2) + "\n\n");

Enumeration enumAtts = m_Instances.enumerateAttributes();

int attIndex = 0;

while (enumAtts.hasMoreElements()) {

Attribute attribute = (Attribute) enumAtts.nextElement();

text.append(attribute.name() + ": "

+ m_Distributions[attIndex][i]);

attIndex++;

}

}

} catch (Exception ex) {

text.append(ex.getMessage());

}

}

return text.toString();

}

}

 

 

 

 


Previous Next

 

Copyright Nelson Flores 2001.

Departamento de Ciencias de la Computacion, Universidad de Chile.