Ejecución de pruebas

Clasificación de Naive Bayes con C#

James McCaffrey

Descargar el ejemplo de código

 

La clasificación de Naive Bayes es una técnica con una tecnología de aprendizaje que se puede usar para predecir a qué categoría en especial pertenece determinado caso de datos. En este artículo, explicaré cómo funciona la clasificación de Naive Bayes y presentaré un ejemplo codificado con el lenguaje C#.

Hay muchas herramientas independientes disponibles que pueden realizar la clasificación de Naive Bayes. Sin embargo, dichas herramientas pueden resultar difíciles o imposibles de integrar directamente en su aplicación y es posible que sea complicado personalizarlas para que se adapten a sus necesidades específicas. También es posible que tengan problemas de copyright ocultos. Este artículo le proporcionará una base sólida para agregar características de la clasificación de Naive Bayes a una aplicación .NET, sin tener que depender de dependencias externas.

La mejor manera de entender lo que es la clasificación de Naive Bayes y de comprender lo que pretendo con este artículo, es examinar la captura de pantalla de un programa de demostración en la Figura 1. El programa de demostración comienza al generar 40 líneas de datos que se usarán para entrenar al clasificador. En la mayoría de los casos se usa un origen de datos existente, en esta ocasión generé datos ficticios para que la demostración sea sencilla. La primera línea de datos es "administrative,right,72.0,female". El primer campo es la profesión (occupation), el segundo se refiere al dominio de mano (hand dominance), el tercero es la estatura en pulgadas (height in inches) y el cuarto se refiere al género (sex). La meta del clasificador es predecir el género de cierto conjunto de valores para obtener la profesión, el dominio y la estatura. Ya que la variable dependiente de género tiene dos valores posibles, este es un ejemplo de clasificación binaria.

Naive Bayes Classification Demo
Figura 1 Demostración de la clasificación de Naive Bayes

Después de generar los datos sin precisión, el programa de demostración convierte cada campo numérico de estatura en una categoría: baja, mediana o alta, mediante la técnica de discretización. Como ya explicaré más adelante, discretizar los datos numéricos en datos de categoría es un enfoque que tiene ventajas y desventajas. Una vez que se discreticen los datos de entrenamiento, el programa de demostración examina las 40 líneas de datos de categoría y calcula los recuentos en conjunto. Por ejemplo, el número de casos de datos en los que la profesión de la persona es administrativa y el género es masculino es 2. De manera adicional, se calculan los números totales de cada valor dependiente (el atributo que se va a predecir, en este ejemplo es masculino o femenino). Como puede ver, hay 24 hombres y 16 mujeres en los datos de entrenamiento.

El programa de demostración ya cuenta con toda la información necesaria para clasificar el género de un nuevo caso de datos, en el que la profesión es educación, el dominio de mano es diestro/a y la estatura es alto/a. En este ejemplo, resulta que la demostración determinó que la posibilidad de que el caso de datos sea masculino es de 0.3855 y de 0.6145 que sea femenino, por lo tanto, el sistema concluye que es muy probable que el caso de datos sea femenino.

En las secciones que siguen, primero explicaré exactamente cómo funciona la clasificación de Naive Bayes, lo guiaré a través del código en el programa de demostración y describiré cómo modificar la demostración para que se adapte a sus necesidades. Este artículo da por sentado que usted tiene (al menos) habilidades básicas de programación con lenguaje de familia C, pero no asume que sabe algo de la clasificación de Naive Bayes. El código para el programa de demostración es un poco largo como para presentarlo en su totalidad en este artículo, puede descargar el origen completo desde el sitio de descarga de MSDN en archive.msdn.microsoft.com/mag201302TestRun.

Cómo funciona la clasificación de Naive Bayes

Vamos a usar el ejemplo que se muestra en la Figura 1, la meta es predecir el género (masculino o femenino) de una persona que trabaja en el campo de la educación, que es diestra y de estatura alta (superior o igual a 71.0 pulgadas [1.80 m]). Para hacerlo, podemos calcular la probabilidad de que el género sea masculino o femenino (según la información) y luego predecir el género con la probabilidad más alta. Si lo expresamos simbólicamente, queremos saber la P(male | X), que por lo general significa: "la probabilidad de que sea masculino según los valores independientes de X" y P(female | X), donde X es (education [educación], diestro/a [right], alto/a [tall]). El término "naive", en Naive Bayes, significa que se da por hecho que todos los atributos X son matemáticamente independientes, lo que hace que la clasificación sea mucho más sencilla. Puede encontrar muchas referencias en línea que explican lo interesante que pueden ser las matemáticas detrás de la clasificación de Naive Bayes, pero el resultado es relativamente sencillo. Simbólicamente:

P(male | X) =
  [ P(education | male) * P(right | male) * P(tall | male) * P(male) ] /
    [ PP(male | X) + PP(female | X) ]

Observe que la ecuación es una fracción. El numerador, a veces llamado probabilidad parcial, consiste en cuatro términos multiplicados entre sí. En este artículo uso la notación no convencional de PP para un término de probabilidad parcial. El denominador es la suma de dos términos, uno de los cuales es el numerador. La primera parte a calcular es P (education | male)o la probabilidad de que la profesión de una persona sea la educación, dado su género masculino. Esto, como veremos, se puede calcular según el número de casos de entrenamientos en los que la profesión es la educación y el género es masculino, dividido por el número de casos que son masculinos (con cualquier profesión), así que:

P(education | male ) = count(education & male) / count(male) = 2/24 = 0.0833

Usando la misma lógica:

P(right | male) = count(right & male) / count(male) = 17/24 = 0.7083
P(tall | male) = count(tall & male) / count(male) = 4/24 = 0.1667

La siguiente pieza del rompecabezas es P(male). En terminología de Naive Bayes, a esto se le llama anterior. Existen algunos debates sobre la mejor manera de calcular anteriores. Por otro lado, podemos suponer que no hay razones para creer que la presencia de hombres es más o menos similar a la presencia de mujeres, así que se puede asignar 0.5 a P(male). Por otra parte, podemos aprovechar el hecho de que los datos de entrenamiento tengan 24 hombres y 16 mujeres, para calcular una probabilidad de 24/40 = 0.6000 para P(male). Prefiero este enfoque, en el que los anteriores se calculan con los datos de entrenamiento.

Ahora bien, si se fija en la ecuación anterior para P(male | X), notará que contiene el PP(female | X). A veces se le llama prueba a la suma inferior, PP(male | X) + PP(female | X). Las piezas para PP(female | X) se calculan de la siguiente manera:

P(education | female) = count(education & female) / count(female) = 4/16 = 0.2500
P(right | female) = count(right & female) / count(female) = 14/16 = 0.8750
P(tall | female) = count(tall & female) / count(female) = 2/16 = 0.1250
P(female) = 16/40 = 0.4000

Así que el numerador de probabilidad parcial para P(male | X) es:

PP(male | X) = 0.0833 * 0.7083 * 0.1667 * 0.6000 = 0.005903

Usando la misma lógica, la probabilidad parcial para femenino según X = (education, right, tall) es:

PP(female | X) = 0.2500 * 0.8750 * 0.1250 * 0.4000 = 0.010938

Y finalmente, las probabilidades de masculino y femenino en general son:

P(male | X) = 0.005903 / (0.005903 + 0.010938) = 0.3505
P(female | X) = 0.010938 / (0.005903 + 0.010938) = 0.6495

A veces se les llama posteriores a estas probabilidades en general. Ya que P(female | X) es mayor que P(male | X), el sistema concluye que el género de las personas desconocidas es femenino. Pero espere. Estas dos probabilidades, 0.3505 y 0.6495, se parecen pero no son iguales a las probabilidades 0.3855 y 0.6145, que aparecen en la Figura 1. La razón de esta discrepancia es que el programa de demostración usa una importante modificación opcional de Naive Bayes básico, llamada Laplacian smoothing.

Laplacian Smoothing

Si consulta la Figura 1, verá que la cantidad de casos de entrenamiento en los cuales la profesión de la persona = construcción y género = femenino es 0. En la demostración, los valores X son (education, right, tall), que no incluyen construcción. Pero supongamos que X hubiera sido (construction, right, tall). En el cálculo de PP(female | X) tendríamos que calcular P(construction | female) = count(construction & female) / count(female), lo que hubiera resultado en 0 y habría llevado a cero toda la probabilidad parcial. En resumen, es malo cuando un recuento en conjunto (joint count) da 0. La técnica más común para evitar esta situación es simplemente agregar 1 a todos los recuentos en conjunto. Esto parece obra de hackers, pero en realidad tiene una base matemática sólida. La técnica se llama add-one smoothing, que es un tipo específico de Laplacian smoothing.

Con Laplacian smoothing, si X = (education, right, tall) como en la sección anterior, se calculan P(male | X) y P(female | X) de la siguiente manera:

P(education | male ) =
  count(education & male) + 1 / count(male) + 3 = 3/27 = 0.1111
P(right | male) =
  count(right & male) + 1 / count(male) + 3 = 18/27 = 0.6667
P(tall | male) =
  count(tall & male) + 1 / count(male) + 3 = 5/27 = 0.1852
P(male) = 24/40 = 0.6000
P(education | female) =
  count(education & female) + 1 / count(female) + 3 = 5/19 = 0.2632
P(right | female) =
  count(right & female) + 1 / count(female) + 3 = 15/19 = 0.7895
P(tall | female) =
  count(tall & female) + 1 / count(female) + 3 = 3/19 = 0.1579
P(female) = 16/40 = 0.4000

Las probabilidades parciales son:

PP(male | X) = 0.1111 * 0.6667 * 0.1852 * 0.6000 = 0.008230
PP(female | X) = 0.2632 * 0.7895 * 0.1579 * 0.4000 = 0.013121

Entonces, las dos probabilidades finales son:

P(male | X) = 0.008230 / (0.008230 + 0.013121) = 0.3855
P(female | X) = 0.013121 / (0.008230 + 0.013121) = 0.6145

Estos son los valores que se muestran en la captura de pantalla de la Figura 1. Observe que se agrega 1 a cada recuento en conjunto, pero se agrega 3 a los denominadores count(male) y count(female). El 3 es de alguna manera arbitrario, en el sentido que Laplacian smoothing no especifica ningún valor en especial a usar. En este caso, es el número de atributos X (occupation, dominance, height). Este es el valor más común que se agrega a los denominadores de probabilidades parciales en Laplacian smoothing, pero tal vez le gustaría experimentar con otros valores. Al valor que se le agrega al denominador a menudo se le asigna el símbolo k, según la literatura matemática de Naive Bayes. Además, observe que por lo general, los anteriores P(male) y P(female) no sufren modificaciones en Laplacian smoothing de Naive Bayes.

Estructura general del programa

El programa de demostración que aparece en ejecución en la Figura 1 es una sola aplicación de consola C#. El método Main, sin algunos de los enunciados WriteLine, se muestra en la Figura 2.

Figura 2 Estructura del programa Naive Bayes

using System;
namespace NaiveBayes
{
  class Program
  {
    static Random ran = new Random(25); // Arbitrary
    static void Main(string[] args)
    {
      try
      {
        string[] attributes = new string[] { "occupation", "dominance",
          "height", "sex"};
        string[][] attributeValues = new string[attributes.Length][];
        attributeValues[0] = new string[] { "administrative",
          "construction", "education", "technology" };
        attributeValues[1] = new string[] { "left", "right" };
        attributeValues[2] = new string[] { "short", "medium", "tall" };
        attributeValues[3] = new string[] { "male", "female" };
        double[][] numericAttributeBorders = new double[1][];
        numericAttributeBorders[0] = new double[] { 64.0, 71.0 };
        string[] data = MakeData(40);
        for (int i = 0; i < 4; ++i)
          Console.WriteLine(data[i]);
        string[] binnedData = BinData(data, attributeValues,
          numericAttributeBorders);
        for (int i = 0; i < 4; ++i)
          Console.WriteLine(binnedData[i]);
        int[][][] jointCounts = MakeJointCounts(binnedData, attributes,
          attributeValues);
        int[] dependentCounts = MakeDependentCounts(jointCounts, 2);
        Console.WriteLine("Total male = " + dependentCounts[0]);
        Console.WriteLine("Total female = " + dependentCounts[1]);
        ShowJointCounts(jointCounts, attributeValues);
        string occupation = "education";
        string dominance = "right";
        string height = "tall";
        bool withLaplacian = true;
        Console.WriteLine(" occupation = " + occupation);
        Console.WriteLine(" dominance = " + dominance);
        Console.WriteLine(" height = " + height);
        int c = Classify(occupation, dominance, height, jointCounts,
          dependentCounts, withLaplacian, 3);
        if (c == 0)
          Console.WriteLine("\nData case is most likely male");
        else if (c == 1)
          Console.WriteLine("\nData case is most likely female");
        Console.WriteLine("\nEnd demo\n");
      }
      catch (Exception ex)
      {
        Console.WriteLine(ex.Message);
      }
    } // End Main
    // Methods to create data
    // Method to bin data
    // Method to compute joint counts
    // Helper method to compute partial probabilities
    // Method to classify a data case
  } // End class Program
}

El programa comienza al establecer los atributos X codificados como profesión (occupation), dominio (dominance) y estatura (height), más el género del atributo dependiente. El algunos casos, es posible que prefiera examinar su origen de datos existente para determinar los atributos, especialmente cuando el origen es un archivo de datos con encabezados o una tabla SQL con nombres de columnas. El programa de demostración también especifica los nueve valores categóricos del atributo X: (administrative, construction, education, technology) para profesión; (left, right) para dominio y (short, medium, tall) para estatura. En este ejemplo, hay dos valores de atributo de variable dependiente: (male, female) para el género. Tal vez le gustaría determinar los valores del atributo mediante programación al explorar sus datos.

La demostración establece valores límite codificados de 64.0 y 71.0 para discretizar los valores numéricos altos, de esa forma los valores menores o iguales a 64.0 se clasifican como bajo; la estatura entre 64.0 y 71.0 como medio y la estatura superior o igual a 71.0 es alto. Al discretizar los datos numéricos para Naive Bayes, el número de valores límite será uno menos que el número de categorías. En este ejemplo, los valores 64.0 y 71.0 se determinaron al examinar los datos de entrenamiento para encontrar valores de estatura mínimos y máximos (57.0 and 78.0), al calcular la diferencia (21.0) y luego al calcular el tamaño de intervalo al dividir por números las categorías de estatura (3), lo que da como resultado 7.0. En la mayoría de los casos, es probable que quiera determinar los valores límites para los atributos numéricos X mediante programación más que a través de una forma manual.

El programa de demostración llama al método auxiliar MakeData para que genere datos de entrenamiento algo aleatorios. MadeData llama a los auxiliares MakeSex, MakeOccupation, MakeDominance y MakeHeight. Por ejemplo, estos auxiliares generan datos para que sea más probable que las profesiones del género masculino sean construcción y tecnología, para que el dominio sea diestro y para que la estatura esté entre las 66.0 y 72.0 pulgadas.

Los métodos clave llamados en Main son BinData (para clasificar los datos de estatura), MakeJointCounts (para explorar los datos discretizados y calcular los recuentos en conjunto), MakeDependentCounts (para calcular el número total de hombres y mujeres) y Classify, que usa recuentos en conjunto y recuentos dependientes para realizar una clasificación de Naive Bayes.

Datos discretizados

El método BinData aparece en la Figura 3. Este método acepta una matriz de cadenas delimitadas por coma, en la que cada cadena se ve como “education,left,67.5,male". En varias ocasiones se encontrará leyendo datos de entrenamiento de un archivo de texto, donde cada línea es una cadena. El método usa String.Split para transformar cada cadena en token. El Token[2] es la estatura. Se convierte de una cadena a un tipo doble, mediante el método double.Parse. La estatura numérica se compara con los valores límite, hasta que se encuentre su intervalo. Luego, se determina la categoría de estatura correspondiente como cadena. La cadena resultante se une mediante tokens antiguos, delimitadores de coma y la nueva categoría de cadena de estatura calculada.

Figura 3 Método BinData para clasificar la estatura

static string[] BinData(string[] data, string[][] attributeValues,
  double[][] numericAttributeBorders)
{
  string[] result = new string[data.Length];
  string[] tokens;
  double heightAsDouble;
  string heightAsBinnedString;
  for (int i = 0; i < data.Length; ++i)
  {
    tokens = data[i].Split(',');
    heightAsDouble = double.Parse(tokens[2]);
    if (heightAsDouble <= numericAttributeBorders[0][0]) // Short
      heightAsBinnedString = attributeValues[2][0];
    else if (heightAsDouble >= numericAttributeBorders[0][1]) // Tall
      heightAsBinnedString = attributeValues[2][2];
    else
      heightAsBinnedString = attributeValues[2][1]; // Medium
    string s = tokens[0] + "," + tokens[1] + "," + heightAsBinnedString +
      "," + tokens[3];
    result[i] = s;
  }
  return result;
}

No es un requisito para discretizar datos numéricos al realizar una clasificación de Naive Bayes. Naives Bayes puede lidiar directamente con los datos numéricos, pero esas técnicas están fuera del alcance de este artículo. Discretizar datos tiene la ventaja de que es sencillo y que se evita tener que hacer cualquier suposición explícita sobre la distribución matemática (como Gaussian o Poisson) de los datos. Sin embargo, la discretización básicamente pierde información y necesita que sea usted quien determine en cuántas categorías quiere dividir los datos.

Determinar recuentos en conjunto

La clave para la clasificación Naive Bayes es calcular recuentos en conjunto. En el ejemplo de demostración, hay nueve valores de atributo de X independientes (administrative, construction, … tall) y dos valores de atributo dependientes (male, female), así que se deben calcular y almacenar un total de 9 * 2 = 18 recuentos en conjunto. Mi enfoque favorito es almacenar los recuentos en conjunto en una matriz tridimensional int[][][] jointCounts. El primer índice indica el atributo X independiente, el segundo indica el valor del atributo X independiente y el tercero indica el valor del atributo dependiente. Por ejemplo, jointCounts[0][3][1] significa: atributo 0 (occupation), valor de atributo 3 (technology) y género 1 (female), en otras palabras, el valor de jointCounts[0][3][1] es el recuento de los casos de entrenamiento en los que la profesión es tecnología y el género es femenino. El método MakeJointCounts aparece en la Figura 4.

Figura 4 Método MakeJointCounts

static int[][][] MakeJointCounts(string[] binnedData, string[] attributes,
  string[][] attributeValues)
{
  int[][][] jointCounts = new int[attributes.Length - 1][][]; // -1 (no sex)
  jointCounts[0] = new int[4][]; // 4 occupations
  jointCounts[1] = new int[2][]; // 2 dominances
  jointCounts[2] = new int[3][]; // 3 heights
  jointCounts[0][0] = new int[2]; // 2 sexes for administrative
  jointCounts[0][1] = new int[2]; // construction
  jointCounts[0][2] = new int[2]; // education
  jointCounts[0][3] = new int[2]; // technology
  jointCounts[1][0] = new int[2]; // left
  jointCounts[1][1] = new int[2]; // right
  jointCounts[2][0] = new int[2]; // short
  jointCounts[2][1] = new int[2]; // medium
  jointCounts[2][2] = new int[2]; // tall
  for (int i = 0; i < binnedData.Length; ++i)
  {
    string[] tokens = binnedData[i].Split(',');
    int occupationIndex = AttributeValueToIndex(0, tokens[0]);
    int dominanceIndex = AttributeValueToIndex(1, tokens[1]);
    int heightIndex = AttributeValueToIndex(2, tokens[2]);
    int sexIndex = AttributeValueToIndex(3, tokens[3]);
    ++jointCounts[0][occupationIndex][sexIndex];
    ++jointCounts[1][dominanceIndex][sexIndex];
    ++jointCounts[2][heightIndex][sexIndex];
  }
  return jointCounts;
}

La implementación tiene muchos valores codificados, esto es para que sea más fácil de entender. Por ejemplo, estas tres declaraciones se podrían reemplazar por un solo bucle for, que ubica el espacio mediante propiedades de Lenght en la matriz attributeValues:

jointCounts[0] = new int[4][]; // 4 occupations
jointCounts[1] = new int[2][]; // 2 dominances
jointCounts[2] = new int[3][]; // 3 heights

La función auxiliar AttributeValueToIndex acepta un índice de atributo y una cadena de atributo de valor, luego devuelve el índice adecuado. Por ejemplo, AttributeValueToIndex(2, “medium”) devuelve el índice de "medium" al atributo de estatura, que es 1.

El programa de demostración usa un método MakeDependentCounts para determinar el número de casos de datos masculinos y femeninos. Existen muchas maneras de hacerlo. Si consulta la Figura 1, podrá ver que un enfoque tiene que agregar el número de los recuentos en conjunto de cualquiera de los tres atributos. Por ejemplo, el número de hombres es la suma de count(administrative & male), count(construction & male), count(education & male) y count(technology & male):

static int[] MakeDependentCounts(int[][][] jointCounts,
  int numDependents)
{
  int[] result = new int[numDependents];
  for (int k = 0; k < numDependents; ++k) 
  // Male then female
    for (int j = 0; j < jointCounts[0].Length; ++j)
    // Scanning attribute 0
      result[k] += jointCounts[0][j][k];
  return result;
}

Clasificación de un caso de datos

El método Classify, que aparece en la Figura 5, es breve ya que depende de métodos auxiliares.

Figura 5 Método Classify

static int Classify(string occupation, string dominance, string height,
  int[][][] jointCounts, int[] dependentCounts, bool withSmoothing,
  int xClasses)
{
  double partProbMale = PartialProbability("male", occupation, dominance,
    height, jointCounts, dependentCounts, withSmoothing, xClasses);
  double partProbFemale = PartialProbability("female", occupation, dominance,
    height, jointCounts, dependentCounts, withSmoothing, xClasses);
  double evidence = partProbMale + partProbFemale;
  double probMale = partProbMale / evidence;
  double probFemale = partProbFemale / evidence;
  if (probMale > probFemale) return 0;
  else return 1;
}

El método Classify acepta las matrices jointCounts y dependentCounts, un campo Booleano que indica si usar o no Laplacian smoothing y el parámetro xClasses, que en este ejemplo será 3, ya que hay tres variables independientes (occupation, dominance, height). También se puede inferir este parámetro del parámetro jointCounts.

El método Classify devuelve un int que representa el índice de la variable dependiente que se predijo. En vez de eso, tal vez le gustaría devolver una matriz de posibilidades para cada variable dependiente. Observe que la clasificación se basa en probMale y probFemale, los que se calculan al dividir probabilidades parciales por el valor de prueba. Tal vez quiera simplemente omitir el término prueba y comparar los valores de las probabilidades parciales entre sí.

El método Classify devuelve el índice de la variable dependiente que tiene la probabilidad más alta. Una alternativa es proporcionar un valor de umbral. Por ejemplo, supongamos que probMale es 0.5001 y probFemale es 0.4999. Tal vez le gustaría considerar que estos valores están demasiado cerca como para llamar y devolver un valor de clasificación que representa lo "indeterminado".

El método PartialProbability hace la mayor parte del trabajo de Classify y aparece en la Figura 6.

Figura 6 Método PartialProbability

static double PartialProbability(string sex, string occupation, string dominance,
  string height, int[][][] jointCounts, int[] dependentCounts,
  bool withSmoothing, int xClasses)
{
  int sexIndex = AttributeValueToIndex(3, sex);
  int occupationIndex = AttributeValueToIndex(0, occupation);
  int dominanceIndex = AttributeValueToIndex(1, dominance);
  int heightIndex = AttributeValueToIndex(2, height);
  int totalMale = dependentCounts[0];
  int totalFemale = dependentCounts[1];
  int totalCases = totalMale + totalFemale;
  int totalToUse = 0;
  if (sex == "male") totalToUse = totalMale;
  else if (sex == "female") totalToUse = totalFemale;
  double p0 = (totalToUse * 1.0) / (totalCases); // Prob male or female
  double p1 = 0.0;
  double p2 = 0.0;
  double p3 = 0.0;
  if (withSmoothing == false)
  {
    p1 = (jointCounts[0][occupationIndex][sexIndex] * 1.0) / totalToUse
    p2 = (jointCounts[1][dominanceIndex][sexIndex] * 1.0) / totalToUse;  
    p3 = (jointCounts[2][heightIndex][sexIndex] * 1.0) / totalToUse;     
  }
  else if (withSmoothing == true)
  {
    p1 = (jointCounts[0][occupationIndex][sexIndex] + 1) /
     ((totalToUse + xClasses) * 1.0); 
    p2 = (jointCounts[1][dominanceIndex][sexIndex] + 1) /
     ((totalToUse + xClasses) * 1.0 ;
    p3 = (jointCounts[2][heightIndex][sexIndex] + 1) /
     ((totalToUse + xClasses) * 1.0);
  }
  //return p0 * p1 * p2 * p3; // Risky if any very small values
  return Math.Exp(Math.Log(p0) + Math.Log(p1) + Math.Log(p2) + Math.Log(p3));
}

El método PartialProbability se codifica principalmente para obtener claridad. Por ejemplo, hay cuatro partes de probabilidad, p0, p1, p2 y p3. Puede hacer que PartialProbability sea más general al usar una matriz de probabilidades, donde el tamaño de la matriz se determine desde la matriz de jointCounts.

Observe que en vez de devolver el producto de las cuatro partes de probabilidad, el método devuelve la Exp equivalente de la suma del Log de cada parte. Usar las probabilidades de log es una técnica estándar en los algoritmos de tecnología de aprendizaje, los que usan para evitar errores numéricos que podrían ocurrir con valores numéricos reales muy pequeños.

Conclusión

El ejemplo que se presenta aquí debería entregarle una buena base para agregar características de clasificación de Naive Bayes a sus aplicaciones .Net. La clasificación de Naive Bayes es una técnica relativamente rudimentaria, pero tiene varias ventajas sobre otras alternativas más sofisticadas, como la clasificación de redes neuronales, la clasificación de regresión logística y la clasificación de máquina de vectores de soporte. Naive Bayes es sencillo, relativamente fácil de implementar y escala bien a grandes conjuntos de datos. Además, Naive Bayes se extiende fácilmente a problemas de clasificación multinominales, aquellos con tres o más variables dependientes.

El Dr. James McCaffrey trabaja en Volt Information Sciences Inc., donde está a cargo del entrenamiento técnico de los ingenieros informáticos que trabajan en el campus de Microsoft en Redmond, Washington. Ha colaborado en el desarrollo de varios productos de Microsoft como, por ejemplo, Internet Explorer y MSN Search. Es el autor de “.NET Test Automation Recipes” (Apress, 2006) y se puede ubicar en la dirección de correo electrónico jammc@microsoft.com.

Gracias al siguiente experto técnico de Microsoft por su ayuda en la revisión de este artículo: Rich Caruana