Учебник. Анализ мнений пользователей в комментариях с веб-сайта с помощью двоичной классификации в ML.NET

В этом руководстве показано, как создать консольное приложение .NET Core, которое классифицирует мнения, выраженные в комментариях с веб-сайта, и предпринимает соответствующие действия. Двоичный классификатор тональности использует C# в Visual Studio 2022.

В этом руководстве вы узнаете, как:

  • Создание консольного приложения
  • Подготовка данных
  • Загрузка данных
  • Сборка и обучение модели
  • Оценка модели
  • Использование модели для прогноза
  • Просмотр результатов

Исходный код для этого руководства можно найти в репозитории dotnet/samples.

Предварительные требования

Создание консольного приложения

  1. Создайте консольное приложение C# с именем "SentimentAnalysis". Нажмите кнопку Далее.

  2. Выберите .NET 6 в качестве используемой платформы. Нажмите кнопку Создать .

  3. Создайте каталог с именем Data в проекте, чтобы сохранять файлы набора данных.

  4. Установите пакет NuGet для Microsoft.ML:

    Примечание

    В этом примере используется последняя стабильная версия пакетов NuGet, упомянутых выше, если не указано иное.

    В обозревателе решений щелкните проект правой кнопкой мыши и выберите Управление пакетами NuGet. Выберите nuget.org в качестве источника пакета, а затем выберите вкладку Обзор. Найдите Microsoft.ML, выберите пакет и нажмите кнопку Установить. Продолжите установку, соглашаясь с условиями лицензии для выбранного пакета.

подготавливать данные;

Примечание

Наборы данных для этого руководства относятся к разделам "От группы к отдельным меткам с помощью глубоких функций", Kotzias et. Аль. KDD 2015, и размещены в репозитории машинного обучения UCI Д. Дуа (D. Dua) и Э. Карра Танискиду (E. Karra Taniskidou) (2017). UCI Machine Learning Repository (Репозиторий машинного обучения UCI) [http://archive.ics.uci.edu/ml ]. Ирвайн, Калифорния: Калифорнийский университет, Школа информационных технологий и компьютерных наук.

  1. Скачайте ZIP-файл набора данных предложений с меткой тональности UCI и извлеките его содержимое.

  2. Скопируйте файл yelp_labelled.txt в созданный каталог Data.

  3. В обозревателе решений щелкните правой кнопкой мыши файл yelp_labeled.txt и выберите пункт Свойства. В разделе Дополнительно для параметра Копировать в выходной каталог установите значение Копировать более позднюю версию.

Создание классов и определение путей

  1. Добавьте следующие новые операторы using в начало файла Program.cs:

    using Microsoft.ML;
    using Microsoft.ML.Data;
    using SentimentAnalysis;
    using static Microsoft.ML.DataOperationsCatalog;
    
  2. Добавьте следующий код в строку прямо под операторами using, чтобы создать поле для хранения недавно скачанного пути к файлу набора данных:

    string _dataPath = Path.Combine(Environment.CurrentDirectory, "Data", "yelp_labelled.txt");
    
  3. Затем создайте классы для входных данных и прогнозов. Добавьте в проект новый класс:

    • В обозревателе решений щелкните проект правой кнопкой мыши и выберите пункты Добавить>Новый элемент.

    • В диалоговом окне Добавление нового элемента выберите Класс и измените значение поля Имя на SentimentData.cs. Теперь нажмите кнопку Добавить.

  4. Файл SentimentData.cs откроется в редакторе кода. Добавьте следующий оператор using в начало файла SentimentData.cs.

    using Microsoft.ML.Data;
    
  5. Удалите из файла SentimentData.cs существующее определение класса и добавьте следующий код с двумя классами SentimentData и SentimentPrediction:

    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; }
    }
    

Как вы подготовили данные

Класс входного набора данных, SentimentData, имеет string для комментариев пользователя (SentimentText) и bool (Sentiment) значение 1 (положительная) или 0 (отрицательная) для определения тональности. Оба поля имеют атрибуты LoadColumn, которые описывают порядок файла данных каждого поля. Кроме того, свойство Sentiment имеет атрибутColumnName, чтобы обозначить его как поле Label. В примере файла ниже отсутствует строка заголовка. Сам файл выглядит следующим образом:

SentimentText Тональность (метка)
Официантка немного медленная. 0
Корочка так себе. 0
Ого... Отличное место. 1
Обслуживание очень быстрое. 1

SentimentPrediction — этот класс прогноза используется после обучения модели. Он наследует от SentimentData таким образом, чтобы входные данные SentimentText могли отображаться вместе с выходными данными прогноза. Логическое значение Prediction является значением, которое модель прогнозирует при предоставлении новых входных данных SentimentText.

Класс выходных данных SentimentPrediction содержит два свойства, вычисляемые в модели: Score — необработанная оценка, вычисляемая в модели, и Probability — оценка, откалиброванная по вероятности того, что текст имеет положительную тональность.

В этом учебнике самым важным свойством является Prediction.

Загрузка данных

Данные на ML.NET представлены интерфейсом IDataView. IDataView позволяет гибко и полно описывать табличные данные (числовые и текстовые). Данные можно загружать в объект IDataView из текстового файла или в режиме реального времени (например, из базы данных SQL или файлов журнала).

Класс MLContext является отправной точкой для всех операций ML.NET. Инициализация mlContext создает новую среду ML.NET, которую могут совместно использовать объекты рабочего процесса создания модели. По существу он аналогичен классу DBContext в Entity Framework.

Необходимо подготовить приложение и затем загружать данные.

  1. Замените строку Console.WriteLine("Hello World!") следующим кодом, чтобы объявить и инициализировать переменную mlContext:

    MLContext mlContext = new MLContext();
    
  2. Добавьте приведенный ниже код в качестве следующей строки кода:

    TrainTestData splitDataView = LoadData(mlContext);
    
  3. Создайте метод LoadData() в нижней части файла Program.cs, используя следующий код:

    TrainTestData LoadData(MLContext mlContext)
    {
    
    }
    

    Метод LoadData() выполняет следующие задачи:

    • загрузка данных;
    • Разделяет скачанный набор данных на наборы данных для обучения и тестирования.
    • Возвращает два набора данных — для обучения и для тестирования.
  4. Добавьте следующий код в первую строку метода LoadData():

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

    Метод LoadFromTextFile() определяет схему данных и считывает файл. Он принимает переменные, содержащие пути к данным, и возвращает объект IDataView.

Разделение набора данных для обучения и тестирования модели

При подготовке модели можно использовать часть набора данных для обучения, а другую часть — для проверки точности модели.

  1. Чтобы разделить скачанные данные на необходимые наборы данных, добавьте код в следующей строке метода LoadData():

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

    Приведенный выше код использует метод TrainTestSplit(), чтобы разделить загруженный набор данных на учебный и проверочный наборы данных и возвратить их в класс DataOperationsCatalog.TrainTestData. Укажите процент тестовых данных с помощью параметра testFraction. Значение по умолчанию — 10 %, но в этом случае лучше использовать 20 % для оценки большего объема данных.

  2. Верните splitDataView в конце метода LoadData().

    return splitDataView;
    

Сборка и обучение модели

  1. Добавьте следующий вызов метода BuildAndTrainModel под вызовом метода LoadData:

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

    Метод BuildAndTrainModel() выполняет следующие задачи:

    • извлечение и преобразование данных;
    • обучение модели;
    • прогноз тональности на основе тестовых данных;
    • возвращение модели.
  2. Создайте метод BuildAndTrainModel() под методом LoadData(), используя следующий код:

    ITransformer BuildAndTrainModel(MLContext mlContext, IDataView splitTrainSet)
    {
    
    }
    

Извлечение и преобразование данных

  1. Добавьте следующую строку кода для вызова FeaturizeText:

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

    Метод FeaturizeText() в приведенном выше коде преобразует текстовый столбец (SentimentText) в числовой столбец типа ключа Features, который используется алгоритмом машинного обучения: он добавляет его как новый столбец набора данных:

    SentimentText Тональность Функции
    Официантка немного медленная. 0 [0.76, 0.65, 0.44, …]
    Корочка так себе. 0 [0.98, 0.43, 0.54, …]
    Ого... Отличное место. 1 [0.35, 0.73, 0.46, …]
    Обслуживание очень быстрое. 1 [0.39, 0, 0.75, …]

Добавление алгоритма обучения

Это приложение использует алгоритм классификации, который классифицирует элементы или строки данных. Приложение классифицирует комментарии веб-сайта как положительные или отрицательные, поэтому это задача двоичной классификации.

Добавьте задачу машинного обучения к определениям преобразований данных, добавив следующее в следующей строке кода в BuildAndTrainModel():

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

SdcaLogisticRegressionBinaryTrainer — ваш алгоритм обучения классификации. Он добавляется в estimator и принимает SentimentText с присвоенными признаками (Features) и входные параметры Label, чтобы пройти обучение по историческим данным.

Обучение модели

Обучите модель на основе данных splitTrainSet и получите обученную модель, добавив в метод BuildAndTrainModel() следующие строки кода:

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

Метод Fit() обучает модель путем преобразования набора данных и применения обучения.

Возврат обученной модели для оценки

Выполните возврат модели в конце метода BuildAndTrainModel().

return model;

Оценка модели

После обучения модели с помощью проверочных данных производится валидация производительности модели.

  1. Создайте метод Evaluate() сразу после BuildAndTrainModel(), используя следующий код:

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

    Метод Evaluate() выполняет следующие задачи:

    • загрузка тестового набора данных;
    • создание средства оценки BinaryClassification;
    • оценка модели и создание метрик;
    • отображение метрик.
  2. Добавьте вызов нового метода под вызовом метода BuildAndTrainModel, используя следующий код:

    Evaluate(mlContext, model, splitDataView.TestSet);
    
  3. Преобразуйте данные splitTestSet, добавив в метод Evaluate() следующий код:

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

    Предыдущий код использует метод Transform(), чтобы сделать прогнозы для нескольких входных строк тестового набора данных.

  4. Оцените модель, добавив в метод Evaluate() следующую строку кода:

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

После получения прогноза (predictions) метод Evaluate() оценивает модель, сравнивая спрогнозированные значения с фактическими метками (Labels) в тестовом наборе данных, а затем возвращает объект CalibratedBinaryClassificationMetrics как метрики эффективности модели.

Отображение метрик для проверки модели

Воспользуйтесь приведенным ниже кодом, чтобы отобразить метрики.

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 ===============");
  • Метрика Accuracy возвращает точность модели — это доля правильных прогнозов в тестовом наборе.

  • Метрика AreaUnderRocCurve показывает уверенность модели в правильности классификации с положительными и отрицательными классами. Значение AreaUnderRocCurve должно быть максимально близким к единице.

  • Метрика F1Score содержит F1-оценку модели, который является мерой баланса между точностью и полнотой. Значение F1Score должно быть максимально близким к единице.

Прогнозировать результаты для тестовых данных

  1. Создайте метод UseModelWithSingleItem() сразу после метода Evaluate(), вставив в него следующий код:

    void UseModelWithSingleItem(MLContext mlContext, ITransformer model)
    {
    
    }
    

    Метод UseModelWithSingleItem() выполняет следующие задачи:

    • создание отдельного комментария тестовых данных;
    • прогноз тональности на основе тестовых данных;
    • объединение тестовых данных и прогнозов для создания отчетов;
    • отображение результатов прогнозирования.
  2. Добавьте вызов нового метода сразу под вызовом метода Evaluate(), используя следующий код:

    UseModelWithSingleItem(mlContext, model);
    
  3. Давайте добавим следующий код в качестве первой строки в методе UseModelWithSingleItem():

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

    Класс PredictionEngine представляет собой удобный API, позволяющий осуществить прогнозирование на основе единственного экземпляра данных. PredictionEngine не является потокобезопасным. Допустимо использовать в средах прототипов или средах с одним потоком. Для улучшенной производительности и потокобезопасности в рабочей среде используйте службу PredictionEnginePool, которая создает ObjectPool объектов PredictionEngine для использования во всем приложении. См. руководство по использованию PredictionEnginePool в веб-API ASP.NET Core.

    Примечание

    Расширение службы PredictionEnginePool сейчас доступно в предварительной версии.

  4. Добавьте комментарий для проверки прогнозирования обученной модели в методе UseModelWithSingleItem(), создав экземпляр SentimentData:

    SentimentData sampleStatement = new SentimentData
    {
        SentimentText = "This was a very bad steak"
    };
    
  5. Передать тестовые комментарии в PredictionEngine, добавив следующие строки кода в метод UseModelWithSingleItem():

    var resultPrediction = predictionFunction.Predict(sampleStatement);
    

    Функция Predict() создает прогноз по одной строке данных.

  6. Выведите SentimentText и соответствующий прогноз тональности, используя следующий код:

    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();
    

Использование модели для прогнозирования

Развертывание и прогнозирование элементов пакета

  1. Создайте метод UseModelWithBatchItems() сразу после метода UseModelWithSingleItem(), вставив в него следующий код:

    void UseModelWithBatchItems(MLContext mlContext, ITransformer model)
    {
    
    }
    

    Метод UseModelWithBatchItems() выполняет следующие задачи:

    • создание пакетных тестовых данных;
    • прогноз тональности на основе тестовых данных;
    • объединение тестовых данных и прогнозов для создания отчетов;
    • отображение результатов прогнозирования.
  2. Добавьте вызов нового метода сразу под вызовом метода UseModelWithSingleItem(), используя следующий код:

    UseModelWithBatchItems(mlContext, model);
    
  3. Добавьте новые комментарии, чтобы проверить прогнозы обученной модели, в метод UseModelWithBatchItems():

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

Предсказание тональности на основе комментариев

Использование модели для прогнозирования тональности комментариев с помощью метода 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);

Объедините и отобразите прогнозы

Создайте заголовок для результатов с помощью следующего кода:

Console.WriteLine();

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

Так как SentimentPrediction наследуется от SentimentData, Transform() метод заполняет SentimentText прогнозируемыми полями. В ходе обработки ML.NET каждый компонент добавляет столбцы, что упрощает отображение результатов:

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 ===============");

Результаты

Результаты выполнения должны выглядеть примерно так, как показано ниже. Во время обработки отображаются сообщения. Вы можете видеть предупреждения или обработанные сообщения. Для удобства они удалены из следующих результатов.

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 . . .

Поздравляем! Вы успешно создали модель машинного обучения для классификации и прогнозирования тональности сообщений.

Построение успешных моделей — итеративный процесс. Изначально эта модель имеет низкое качество, так как в руководстве используются небольшие наборы данных для быстрого обучения. Если вам требуется модель более высокого качества, можно попытаться улучшить ее, использовав более крупные наборы данных для обучения или выбрав другие алгоритмы обучения с разными гиперпараметрами для каждого алгоритма.

Исходный код для этого руководства можно найти в репозитории dotnet/samples.

Следующие шаги

В этом руководстве вы узнали, как:

  • Создание консольного приложения
  • Подготовка данных
  • Загрузка данных
  • Сборка и обучение модели
  • Оценка модели
  • Использование модели для прогноза
  • Просмотр результатов

Переходите к следующему руководству: