Tutorial: Análisis de opinión de los comentarios del sitio web con clasificación binaria de ML.NET

En este tutorial se muestra cómo crear una aplicación de consola de .NET Core que clasifica las opiniones de los comentarios del sitio web y toma las medidas oportunas. El clasificador binario de opiniones usa C# en Visual Studio 2022.

En este tutorial aprenderá a:

  • Creación de una aplicación de consola
  • Preparar los datos
  • Carga de los datos
  • Creación y entrenamiento del modelo
  • Evaluar el modelo
  • Uso del modelo para realizar una predicción
  • Ver los resultados

Puede encontrar el código fuente para este tutorial en el repositorio dotnet/samples.

Requisitos previos

Creación de una aplicación de consola

  1. Cree una aplicación de consola de C# denominada "SentimentAnalysis". Haga clic en el botón Next (Siguiente).

  2. Seleccione .NET 6 como marco de trabajo que va a usarse. Haga clic en el botón Crear.

  3. Cree un directorio denominado Datos en el proyecto para guardar los archivos del conjunto de datos.

  4. Instale el paquete NuGet Microsoft.ML:

    Nota

    En este ejemplo se usa la versión estable más reciente de los paquetes NuGet mencionados, a menos que se indique lo contrario.

    En el Explorador de soluciones, haga clic con el botón derecho en Administrar paquetes NuGet. Elija "nuget.org" como origen del paquete y luego seleccione la pestaña Examinar. Busque Microsoft.ML, seleccione el paquete que desee y luego, el botón Instalar. Acepte los términos de licencia del paquete que elija para continuar con la instalación.

Preparar los datos

Nota

Los conjuntos de datos de este tutorial proceden de «From Group to Individual Labels using Deep Features», Kotzias et. al. KDD 2015, and hosted at the UCI Machine Learning Repository - Dua, D. and Karra Taniskidou, E. (2017). UCI Machine Learning Repository [http://archive.ics.uci.edu/ml ]. Irvine, CA: University of California, School of Information and Computer Science.

  1. Descargue el archivo ZIP de conjunto de datos de frases con etiqueta de opinión de UCI y descomprímalo.

  2. Copie el archivo yelp_labelled.txt en el directorio Datos que ha creado.

  3. En el Explorador de soluciones, haga clic con el botón derecho en el archivo yelp_labeled.txt y seleccione Propiedades. En Avanzadas, cambie el valor de Copiar en el directorio de salida por Copiar si es posterior.

Crear clases y definir rutas de acceso

  1. Agregue las siguientes instrucciones using adicionales a la parte superior del archivo Program.cs:

    using Microsoft.ML;
    using Microsoft.ML.Data;
    using SentimentAnalysis;
    using static Microsoft.ML.DataOperationsCatalog;
    
  2. Agregue el código siguiente a la línea justo debajo de las instrucciones using para crear un campo que incluya la ruta de acceso del archivo del conjunto de datos descargado recientemente:

    string _dataPath = Path.Combine(Environment.CurrentDirectory, "Data", "yelp_labelled.txt");
    
  3. Luego, cree clases para los datos de entrada y las predicciones. Agregue una nueva clase a su proyecto:

    • En el Explorador de soluciones, haga clic con el botón derecho en el proyecto y, a continuación, seleccione Agregar>Nuevo elemento.

    • En el cuadro de diálogo Agregar nuevo elemento, seleccione Clase y cambie el campo Nombre a SentimentData.cs. A continuación, seleccione el botón Agregar.

  4. Se abre el archivo SentimentData.cs en el editor de código. Agregue la siguiente instrucción using a la parte superior de SentimentData.cs:

    using Microsoft.ML.Data;
    
  5. Quite la definición de clase existente y agregue el código siguiente, que tiene dos clases SentimentData y SentimentPrediction, al archivo SentimentData.cs:

    public class SentimentData
    {
        [LoadColumn(0)]
        public string? SentimentText;
    
        [LoadColumn(1), ColumnName("Label")]
        public bool Sentiment;
    }
    
    public class SentimentPrediction : SentimentData
    {
    
        [ColumnName("PredictedLabel")]
        public bool Prediction { get; set; }
    
        public float Probability { get; set; }
    
        public float Score { get; set; }
    }
    

¿Cómo se han preparado los datos?

La clase de conjunto de datos de entrada, SentimentData, tiene un string para comentarios del usuario (SentimentText) y un valor bool (Sentiment) de 1 (positivo) o de 0 (negativo) para las opiniones. Ambos campos tienen atributos LoadColumn adjuntos a ellos, que describe el orden de archivo de datos de cada campo. Además, la propiedad Sentiment tiene un atributo ColumnName que lo designa como campo Label. El archivo de ejemplo siguiente no tiene una fila de encabezado y se ve así:

SentimentText Opinión (etiqueta)
La camarera era algo lenta en el servicio. 0
La corteza no es buena. 0
¡Ah! Me encantó el lugar. 1
El servicio fue muy rápido. 1

SentimentPrediction es la clase de predicción que se utiliza tras el entrenamiento del modelo. Hereda de SentimentData para que la entrada SentimentText pueda mostrarse junto con la predicción de salida. El booleano Prediction es el valor que predice el modelo cuando se proporciona con la nueva entrada SentimentText.

La clase de salida SentimentPrediction contiene otras dos propiedades calculadas por el modelo: Score, el resultado sin formato calculado por el modelo y Probability, la puntuación calibrada de la probabilidad de que el texto tenga un sentimiento positivo.

Para este tutorial, la propiedad más importante es Prediction.

Carga de los datos

Los datos de ML.NET se representan como una interfaz IDataView. IDataView es una manera flexible y eficiente de describir datos tabulares (numéricos y de texto). Los datos se pueden cargar desde un archivo de texto o en tiempo real (por ejemplo, archivos de registro o base de datos SQL) en un objeto IDataView.

La clase MLContext es un punto de partida para todas las operaciones de ML.NET. La inicialización de mlContext crea un entorno de ML.NET que se puede compartir entre los objetos del flujo de trabajo de creación de modelos. Como concepto, se parece a DBContext en Entity Framework.

Prepare la aplicación y luego cargue datos:

  1. Reemplace la línea Console.WriteLine("Hello World!") por el siguiente código para declarar e inicializar la variable mlContext:

    MLContext mlContext = new MLContext();
    
  2. Agregue lo siguiente como la siguiente línea de código:

    TrainTestData splitDataView = LoadData(mlContext);
    
  3. Cree un método LoadData() al final del archivo Program.cs mediante el código siguiente:

    TrainTestData LoadData(MLContext mlContext)
    {
    
    }
    

    El método LoadData() ejecuta las tareas siguientes:

    • Carga los datos.
    • Divide el conjunto de datos cargado en conjuntos de datos de entrenamiento y prueba.
    • Devuelve los conjuntos de datos divididos en entrenamiento y prueba.
  4. Agregue el código siguiente a la primera línea del método LoadData():

    IDataView dataView = mlContext.Data.LoadFromTextFile<SentimentData>(_dataPath, hasHeader: false);
    

    El método LoadFromTextFile() define el esquema de datos y lee en el archivo. Toma las variables de ruta de acceso de datos y devuelve IDataView.

División del conjunto de datos para el entrenamiento y la prueba del modelo

Al preparar un modelo, se utiliza parte del conjunto de datos para entrenarlo y parte del conjunto de datos para probar la precisión del modelo.

  1. Para dividir los datos cargados en los conjuntos de datos necesarios, agregue el código siguiente como la siguiente línea en el método LoadData():

    TrainTestData splitDataView = mlContext.Data.TrainTestSplit(dataView, testFraction: 0.2);
    

    El código anterior usa el método TrainTestSplit() para dividir el conjunto de datos cargado en conjuntos de datos de entrenamiento y de prueba, que devuelve en la clase DataOperationsCatalog.TrainTestData. Especifique el porcentaje de datos del conjunto de prueba con el parámetro testFraction. El valor predeterminado es 10 %; en este caso se usa 20 % para evaluar más datos.

  2. Devuelva el splitDataView al final del método LoadData():

    return splitDataView;
    

Creación y entrenamiento del modelo

  1. Agregue la siguiente llamada al método BuildAndTrainModel debajo de la llamada al método LoadData:

    ITransformer model = BuildAndTrainModel(mlContext, splitDataView.TrainSet);
    

    El método BuildAndTrainModel() ejecuta las tareas siguientes:

    • Extrae y transforma los datos.
    • Entrena el modelo.
    • Predice sentimientos en función de datos de prueba.
    • Devuelve el modelo.
  2. Cree el método BuildAndTrainModel() debajo del método LoadData() mediante el código siguiente:

    ITransformer BuildAndTrainModel(MLContext mlContext, IDataView splitTrainSet)
    {
    
    }
    

Extraer y transformar los datos

  1. Llame a FeaturizeText como siguiente línea de código:

    var estimator = mlContext.Transforms.Text.FeaturizeText(outputColumnName: "Features", inputColumnName: nameof(SentimentData.SentimentText))
    

    El método FeaturizeText() del código anterior convierte la columna de texto (SentimentText) en una columna de tipo de clave numérico Features que el algoritmo de aprendizaje automático utiliza y agrega como nueva columna de conjunto de datos:

    SentimentText Opinión Características
    La camarera era algo lenta en el servicio. 0 [0,76, 0,65, 0,44, …]
    La corteza no es buena. 0 [0,98, 0,43, 0,54, …]
    ¡Ah! Me encantó el lugar. 1 [0,35, 0,73, 0,46, …]
    El servicio fue muy rápido. 1 [0,39, 0, 0,75, …]

Incorporación de un algoritmo de aprendizaje

Esta aplicación usa un algoritmo de clasificación que clasifica elementos o filas de datos. La aplicación clasifica los comentarios del sitio web como positivos o negativos, así que use la tarea de clasificación binaria.

Anexe la tarea de aprendizaje automático a las definiciones de transformación de datos agregando lo siguiente como siguiente línea de código en BuildAndTrainModel():

.Append(mlContext.BinaryClassification.Trainers.SdcaLogisticRegression(labelColumnName: "Label", featureColumnName: "Features"));

SdcaLogisticRegressionBinaryTrainer es el algoritmo de entrenamiento de clasificación. Se anexa a estimator y acepta SentimentText (Features) caracterizado y los parámetros de entrada Label para aprender de los datos históricos.

Entrenar el modelo

Ajuste el modelo a los datos splitTrainSet y devuelva el modelo entrenado. Para ello, agregue lo que se indica a continuación como la siguiente línea de código en el método BuildAndTrainModel():

Console.WriteLine("=============== Create and Train the Model ===============");
var model = estimator.Fit(splitTrainSet);
Console.WriteLine("=============== End of training ===============");
Console.WriteLine();

El método Fit() entrena el modelo al transformar el conjunto de datos y aplicar el aprendizaje.

Devolución del modelo entrenado para su uso para la evaluación

Devuelva el modelo al final del método BuildAndTrainModel():

return model;

Evaluar el modelo

Cuando el modelo haya sido entrenado, use los datos de prueba para validar su rendimiento.

  1. Cree el método Evaluate(), justo después de BuildAndTrainModel(), con el código siguiente:

    void Evaluate(MLContext mlContext, ITransformer model, IDataView splitTestSet)
    {
    
    }
    

    El método Evaluate() ejecuta las tareas siguientes:

    • Carga el conjunto de datos de prueba.
    • Crea el evaluador BinaryClassification.
    • Evalúa el modelo y crea las métricas.
    • Muestra las métricas.
  2. Agregue una llamada al nuevo método debajo de la llamada de método BuildAndTrainModel mediante el código siguiente:

    Evaluate(mlContext, model, splitDataView.TestSet);
    
  3. Transforme los datos splitTestSet mediante la adición del código siguiente a Evaluate():

    Console.WriteLine("=============== Evaluating Model accuracy with Test data===============");
    IDataView predictions = model.Transform(splitTestSet);
    

    El código anterior usa el método Transform() para realizar predicciones para varias filas de entrada de un conjunto de datos de prueba especificado.

  4. Para evaluar el modelo, agregue lo que se indica a continuación como la siguiente línea de código en el método Evaluate():

    CalibratedBinaryClassificationMetrics metrics = mlContext.BinaryClassification.Evaluate(predictions, "Label");
    

Cuando haya establecido el conjunto de predicción (predictions), el método Evaluate() evalúa el modelo, que compara los valores de predicción con el valor real de Labels en el conjunto de datos de prueba y devuelve un objeto CalibratedBinaryClassificationMetrics sobre cómo se ejecuta el modelo.

Mostrar las métricas para la validación del modelo

Use el siguiente código para mostrar las métricas:

Console.WriteLine();
Console.WriteLine("Model quality metrics evaluation");
Console.WriteLine("--------------------------------");
Console.WriteLine($"Accuracy: {metrics.Accuracy:P2}");
Console.WriteLine($"Auc: {metrics.AreaUnderRocCurve:P2}");
Console.WriteLine($"F1Score: {metrics.F1Score:P2}");
Console.WriteLine("=============== End of model evaluation ===============");
  • La métrica Accuracy obtiene la precisión de un modelo, que corresponde a la proporción de predicciones correctas en el conjunto de pruebas.

  • La métrica AreaUnderRocCurve indica el nivel de confianza del modelo en clasificar correctamente las clases positivas y negativas. Se desea que AreaUnderRocCurve esté lo más cerca de uno posible.

  • La métrica F1Score obtiene la puntuación F1 del modelo, que es una medida del equilibrio entre precisión y recuperación. Se desea que F1Score esté lo más cerca de uno posible.

Predicción del resultado de datos de prueba

  1. Cree el método UseModelWithSingleItem(), justo después del método Evaluate(), mediante el código siguiente:

    void UseModelWithSingleItem(MLContext mlContext, ITransformer model)
    {
    
    }
    

    El método UseModelWithSingleItem() ejecuta las tareas siguientes:

    • Crea un único comentario de datos de prueba.
    • Predice sentimientos en función de datos de prueba.
    • Combina datos de prueba y predicciones para la generación de informes.
    • Muestra los resultados de la predicción.
  2. Agregue una llamada al nuevo método justo debajo de la llamada al método Evaluate() mediante el código siguiente:

    UseModelWithSingleItem(mlContext, model);
    
  3. Agregue el código siguiente como primera línea en el método UseModelWithSingleItem():

    PredictionEngine<SentimentData, SentimentPrediction> predictionFunction = mlContext.Model.CreatePredictionEngine<SentimentData, SentimentPrediction>(model);
    

    PredictionEngine es una API de conveniencia, que le permite realizar una predicción en una única instancia de datos. PredictionEngine no es seguro para subprocesos. Es aceptable usarlo en entornos de un solo subproceso o prototipo. Para mejorar el rendimiento y la seguridad para subprocesos en entornos de producción, use el servicio PredictionEnginePool, que crea un ObjectPool de objetos de PredictionEngine para su uso en toda la aplicación. Consulte esta guía sobre cómo usar PredictionEnginePool en una API web de ASP.NET Core.

    Nota

    La extensión del servicio PredictionEnginePool está actualmente en versión preliminar.

  4. Agregue un comentario para probar la predicción del modelo entrenado en el método UseModelWithSingleItem() mediante la creación de una instancia de SentimentData:

    SentimentData sampleStatement = new SentimentData
    {
        SentimentText = "This was a very bad steak"
    };
    
  5. Pase los datos del comentario de prueba a PredictionEngine agregando lo siguiente como siguientes líneas de código al método UseModelWithSingleItem():

    var resultPrediction = predictionFunction.Predict(sampleStatement);
    

    La función Predict() realiza una predicción sobre una sola fila de datos.

  6. Muestre SentimentText y la predicción de opiniones correspondiente con el código siguiente:

    Console.WriteLine();
    Console.WriteLine("=============== Prediction Test of model with a single sample and test dataset ===============");
    
    Console.WriteLine();
    Console.WriteLine($"Sentiment: {resultPrediction.SentimentText} | Prediction: {(Convert.ToBoolean(resultPrediction.Prediction) ? "Positive" : "Negative")} | Probability: {resultPrediction.Probability} ");
    
    Console.WriteLine("=============== End of Predictions ===============");
    Console.WriteLine();
    

Uso del modelo de predicción

Implementación y predicción de elementos por lotes

  1. Cree el método UseModelWithBatchItems(), justo después del método UseModelWithSingleItem(), mediante el código siguiente:

    void UseModelWithBatchItems(MLContext mlContext, ITransformer model)
    {
    
    }
    

    El método UseModelWithBatchItems() ejecuta las tareas siguientes:

    • Crea datos de prueba por lotes.
    • Predice sentimientos en función de datos de prueba.
    • Combina datos de prueba y predicciones para la generación de informes.
    • Muestra los resultados de la predicción.
  2. Agregue una llamada al nuevo método justo debajo de la llamada al método UseModelWithSingleItem() mediante el código siguiente:

    UseModelWithBatchItems(mlContext, model);
    
  3. Agregue algunos comentarios para probar las predicciones del modelo entrenado en el método UseModelWithBatchItems():

    IEnumerable<SentimentData> sentiments = new[]
    {
        new SentimentData
        {
            SentimentText = "This was a horrible meal"
        },
        new SentimentData
        {
            SentimentText = "I love this spaghetti."
        }
    };
    

Predicción de opiniones de comentarios

Use el modelo para predecir la opinión de datos de comentario con el método Transform():

IDataView batchComments = mlContext.Data.LoadFromEnumerable(sentiments);

IDataView predictions = model.Transform(batchComments);

// Use model to predict whether comment data is Positive (1) or Negative (0).
IEnumerable<SentimentPrediction> predictedResults = mlContext.Data.CreateEnumerable<SentimentPrediction>(predictions, reuseRowObject: false);

Combinación y presentación de las predicciones

Cree un encabezado para las predicciones con el código siguiente:

Console.WriteLine();

Console.WriteLine("=============== Prediction Test of loaded model with multiple samples ===============");

Dado que SentimentPrediction se hereda de SentimentData, el método Transform() rellena SentimentText con los campos de predicción. A medida que el proceso ML.NET se ejecuta, cada componente agrega columnas, y esto facilita la presentación de los resultados:

foreach (SentimentPrediction prediction  in predictedResults)
{
    Console.WriteLine($"Sentiment: {prediction.SentimentText} | Prediction: {(Convert.ToBoolean(prediction.Prediction) ? "Positive" : "Negative")} | Probability: {prediction.Probability} ");
}
Console.WriteLine("=============== End of predictions ===============");

Resultados

Los resultados deberían ser similares a los indicados a continuación. Durante el procesamiento, se muestran mensajes. Puede ver las advertencias o mensajes de procesamiento. Se han quitado de los siguientes resultados para mayor claridad.

Model quality metrics evaluation
--------------------------------
Accuracy: 83.96%
Auc: 90.51%
F1Score: 84.04%

=============== End of model evaluation ===============

=============== Prediction Test of model with a single sample and test dataset ===============

Sentiment: This was a very bad steak | Prediction: Negative | Probability: 0.1027377
=============== End of Predictions ===============

=============== Prediction Test of loaded model with a multiple samples ===============

Sentiment: This was a horrible meal | Prediction: Negative | Probability: 0.1369192
Sentiment: I love this spaghetti. | Prediction: Positive | Probability: 0.9960636
=============== End of predictions ===============

=============== End of process ===============
Press any key to continue . . .

¡Enhorabuena! Ya ha creado correctamente un modelo de aprendizaje automático para clasificar y predecir los sentimientos de los mensajes.

La creación de modelos correctos es un proceso iterativo. Este modelo tiene una calidad inicial más baja, ya que el tutorial utiliza pequeños conjuntos de datos para proporcionar un entrenamiento rápido del modelo. Si no está satisfecho con la calidad del modelo, puede intentar mejorarlo proporcionando conjuntos de datos de entrenamiento más grandes o eligiendo distintos algoritmos de entrenamiento con distintos hiperparámetros para cada algoritmo.

Puede encontrar el código fuente para este tutorial en el repositorio dotnet/samples.

Pasos siguientes

En este tutorial ha aprendido a:

  • Creación de una aplicación de consola
  • Preparar los datos
  • Carga de los datos
  • Creación y entrenamiento del modelo
  • Evaluar el modelo
  • Uso del modelo para realizar una predicción
  • Ver los resultados

Siga con el siguiente tutorial para obtener más información