Tutorial: Analisar sentimento de comentários de um site com classificação binária em ML.NET
Este tutorial mostra como criar um aplicativo de console do .NET Core que classifica sentimentos de comentários de um site e executa a ação adequada. O classificador binário de sentimento usa C# no Visual Studio 2022.
Neste tutorial, você aprenderá a:
- Criar um aplicativo de console
- Preparar dados
- Carregar os dados
- Criar e treinar o modelo
- Avaliar o modelo
- Usar o modelo para fazer uma previsão
- Confira os resultados
Você pode encontrar o código-fonte para este tutorial no repositório dotnet/samples.
Pré-requisitos
Criar um aplicativo de console
Crie um Aplicativo de console em C# chamado "SentimentAnalysis". Clique no botão Avançar.
Escolha o .NET 6 como a estrutura a ser usada. Selecione o botão Criar.
Crie um diretório chamado Data no seu projeto para salvar os arquivos do conjunto de dados.
Instalar o Pacote NuGet Microsoft.ML:
Observação
Este exemplo usa a versão estável mais recente dos pacotes NuGet mencionados, salvo indicação em contrário.
No Gerenciador de Soluções, clique com o botão direito do mouse no seu projeto e selecione Gerenciar Pacotes NuGet. Escolha "nuget.org" como a origem do pacote e selecione a guia Procurar. Procure Microsoft.ML, escolha o pacote desejado e selecione o botão Instalar. Prossiga com a instalação concordando com os termos de licença do pacote que você escolher.
Preparar seus dados
Observação
Os conjuntos de dados deste tutorial são de "From Group to Individual Labels using Deep Features”, Kotzias et. al,. KDD 2015, e hospedados no UCI Machine Learning Repository – Dua, D. e 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.
Baixe o arquivo zip do conjunto de dados de Sentenças de sentimentos rotuladas da UCI e descompacte-o.
Copie o arquivo
yelp_labelled.txt
para o diretório Dados que você criou.No Gerenciador de Soluções, clique com o botão direito do mouse no arquivo
yelp_labeled.txt
e selecione Propriedades. Em Avançado, altere o valor de Copiar para Diretório de Saída para Copiar se for mais novo.
Criar classes e definir demarcadores
Adicione as seguintes instruções
using
adicionais ao início do arquivo Program.cs:using Microsoft.ML; using Microsoft.ML.Data; using SentimentAnalysis; using static Microsoft.ML.DataOperationsCatalog;
Adicione o seguinte código à linha logo abaixo das instruções
using
para criar um campo para manter o caminho de arquivo do conjunto de dados recentemente baixado:string _dataPath = Path.Combine(Environment.CurrentDirectory, "Data", "yelp_labelled.txt");
Em seguida, crie classes para os dados de entrada e as previsões. Adicione uma nova classe ao seu projeto:
No Gerenciador de Soluções, clique com o botão direito do mouse no projeto e selecione Adicionar>Novo Item.
Na caixa de diálogo Adicionar Novo Item, selecione Classe e altere o campo Nome para SentimentData.cs. Em seguida, selecione o botão Adicionar.
O arquivo SentimentData.cs é aberto no editor de códigos. Adicione a seguinte instrução
using
acima de SentimentData.cs:using Microsoft.ML.Data;
Remova a definição de classe existente e adicione o seguinte código, que possui duas classes
SentimentData
eSentimentPrediction
, ao arquivo 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; } }
Como os dados foram preparados
A classe de conjunto de dados de entrada, SentimentData
, tem um string
para comentários do usuário (SentimentText
) e um valor bool
(Sentiment
) de 1 (positivo) ou 0 (negativo) para sentimento. Ambos os campos têm atributos LoadColumn anexados a eles, que descrevem a ordem do arquivo de dados de cada campo. Além disso, a propriedade Sentiment
tem um atributo ColumnName para designá-lo como o campo Label
. O arquivo de exemplo a seguir não possui uma linha de cabeçalho e tem a seguinte aparência:
SentimentText | Sentimento (rótulo) |
---|---|
A garçonete foi um pouco lenta no serviço. | 0 |
A torrada não é boa. | 0 |
Uau! Adorei esse lugar. | 1 |
O serviço era muito rápido. | 1 |
SentimentPrediction
é a classe de previsão usada após o treinamento do modelo. Ela herda SentimentData
de modo que a entrada SentimentText
possa ser exibida junto com a previsão de saída. O booliano Prediction
é o valor que o modelo prevê quando fornecido com a nova entrada SentimentText
.
A classe de saída SentimentPrediction
contém duas outras propriedades calculadas pelo modelo: Score
– a pontuação bruta calculada pelo modelo e Probability
– a pontuação calibrada para a probabilidade de o texto ter sentimento positivo.
Para este tutorial, a propriedade mais importante é Prediction
.
Carregar os dados
Os dados do ML.NET são representados como uma interface IDataView. IDataView
é uma maneira flexível e eficiente de descrever dados tabulares (numéricos e texto). Os dados podem ser carregados de um arquivo de texto ou em tempo real (por exemplo, banco de dados SQL ou arquivos de log) para um objeto IDataView
.
A classe MLContext é um ponto de partida para todas as operações do ML.NET. Inicializar mlContext
cria um novo ambiente do ML.NET que pode ser compartilhado entre os objetos do fluxo de trabalho de criação de modelo. Ele é semelhante, conceitualmente, a DBContext
no Entity Framework.
Você prepara o aplicativo e, em seguida, carrega os dados:
Substitua a linha
Console.WriteLine("Hello World!")
pelo seguinte código para declarar e inicializar a variável mlContext:MLContext mlContext = new MLContext();
Adicione o seguinte como a linha seguinte do código:
TrainTestData splitDataView = LoadData(mlContext);
Crie um método
LoadData()
na parte inferior do arquivoProgram.cs
usando o seguinte código:TrainTestData LoadData(MLContext mlContext) { }
O método
LoadData()
executa as seguintes tarefas:- Carrega os dados.
- Divide o conjunto de dados carregado em conjuntos de treinamento e teste.
- Retorna os conjuntos de treinamento e teste.
Adicione o seguinte código como a primeira linha do método
LoadData()
:IDataView dataView = mlContext.Data.LoadFromTextFile<SentimentData>(_dataPath, hasHeader: false);
O método LoadFromTextFile() define o esquema de dados e lê o arquivo. Ele usa as variáveis de caminho de dados e retorna uma
IDataView
.
Dividir o conjunto de dados para o modelo de treinamento e de teste
Ao preparar um modelo, você usa parte do conjunto de dados para treiná-lo e parte do conjunto de dados para testar a precisão do modelo.
Para dividir os dados carregados nos conjuntos de dados necessários, adicione o seguinte código como a próxima linha no método
LoadData()
:TrainTestData splitDataView = mlContext.Data.TrainTestSplit(dataView, testFraction: 0.2);
O código anterior usa o método TrainTestSplit() para dividir o conjunto de dados carregado em conjuntos de dados de treino e de teste e retorna-os na classe DataOperationsCatalog.TrainTestData. Especifique o percentual de dados do conjunto de teste com o parâmetro
testFraction
. O padrão é 10% e, nesse caso, você usa 20% para avaliar mais dados.Retorne o
splitDataView
no final do métodoLoadData()
:return splitDataView;
Criar e treinar o modelo
Adicione a seguinte chamada ao método
BuildAndTrainModel
abaixo da chamada ao métodoLoadData
:ITransformer model = BuildAndTrainModel(mlContext, splitDataView.TrainSet);
O método
BuildAndTrainModel()
executa as seguintes tarefas:- Extrai e transforma os dados.
- Treina o modelo.
- Prevê o sentimento com base nos dados de teste.
- Retorna o modelo.
Crie o método
BuildAndTrainModel()
, abaixo do métodoLoadData()
, usando o seguinte código:ITransformer BuildAndTrainModel(MLContext mlContext, IDataView splitTrainSet) { }
Extrair e transformar os dados
Chame
FeaturizeText
como a próxima linha de código:var estimator = mlContext.Transforms.Text.FeaturizeText(outputColumnName: "Features", inputColumnName: nameof(SentimentData.SentimentText))
O método
FeaturizeText()
no código anterior converte a coluna de texto (SentimentText
) em uma colunaFeatures
do tipo chave numérica usada pelo algoritmo de aprendizado de máquina, adicionando-a como uma nova coluna do conjunto de dados:SentimentText Sentimento Recursos A garçonete foi um pouco lenta no serviço. 0 [0,76, 0,65, 0,44, …] A torrada não é boa. 0 [0,98, 0,43, 0,54, …] Uau! Adorei esse lugar. 1 [0,35, 0,73, 0,46, …] O serviço era muito rápido. 1 [0,39, 0, 0,75, …]
Adicionar um algoritmo de aprendizado
Este aplicativo usa um algoritmo de classificação que categoriza itens ou linhas de dados. O aplicativo categoriza comentários de site como positivos ou negativos, portanto, use a tarefa de classificação binária.
Acrescente a tarefa de aprendizado de máquina às definições de transformação de dados adicionando o seguinte como a próxima linha de código em BuildAndTrainModel()
:
.Append(mlContext.BinaryClassification.Trainers.SdcaLogisticRegression(labelColumnName: "Label", featureColumnName: "Features"));
O SdcaLogisticRegressionBinaryTrainer é o algoritmo de treinamento de classificação. Ele é acrescentado ao estimator
e aceita o parâmetro SentimentText
(Features
) personalizado e o parâmetro de entrada Label
para aprender com os dados históricos.
Treinar o modelo
Ajuste o modelo aos dados splitTrainSet
e retorne o modelo treinado adicionando o seguinte como a próxima linha de código no método BuildAndTrainModel()
:
Console.WriteLine("=============== Create and Train the Model ===============");
var model = estimator.Fit(splitTrainSet);
Console.WriteLine("=============== End of training ===============");
Console.WriteLine();
O método Fit() treina o modelo transformando o conjunto de dados e aplicando o treinamento.
Retornar o modelo treinado a ser usado para avaliação
Retorne o modelo no final do método BuildAndTrainModel()
:
return model;
Avaliar o modelo
Depois que o modelo é treinado, use os dados de teste para validar o desempenho do modelo.
Crie o método
Evaluate()
, logo apósBuildAndTrainModel()
, com o código a seguir:void Evaluate(MLContext mlContext, ITransformer model, IDataView splitTestSet) { }
O método
Evaluate()
executa as seguintes tarefas:- Carrega o conjunto de dados de teste.
- Cria o avaliador BinaryClassification.
- Avalia o modelo e cria métricas.
- Exibe as métricas.
Adicione uma chamada ao novo método abaixo da chamada do método
BuildAndTrainModel
usando o seguinte código:Evaluate(mlContext, model, splitDataView.TestSet);
Transforme os dados
splitTestSet
adicionando o seguinte código aEvaluate()
:Console.WriteLine("=============== Evaluating Model accuracy with Test data==============="); IDataView predictions = model.Transform(splitTestSet);
O código anterior usa o método Transform para fazer previsões para várias linhas de entrada fornecidas por um conjunto de dados de teste.
Avalie o modelo adicionando o seguinte como a próxima linha de código no método
Evaluate()
:CalibratedBinaryClassificationMetrics metrics = mlContext.BinaryClassification.Evaluate(predictions, "Label");
Uma vez que você tem o conjunto de previsão (predictions
), o método Evaluate() avalia o modelo, que compara os valores previstos com os Labels
reais no conjunto de dados de teste e retorna um objeto CalibratedBinaryClassificationMetrics sobre o desempenho do modelo.
Exibir as métricas para validação de modelo
Use o código a seguir para exibir as 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 ===============");
A métrica
Accuracy
obtém a precisão de um modelo, que é a proporção de previsões corretas no conjunto de teste.A métrica
AreaUnderRocCurve
indica a confiabilidade do modelo ao classificar corretamente as classes positivas e negativas. Você deseja que oAreaUnderRocCurve
seja o mais próximo possível de um.A métrica
F1Score
obtém a pontuação F1 do modelo, que é uma medida do equilíbrio entre precisão e recall. Você deseja que oF1Score
seja o mais próximo possível de um.
Prever o resultado dos dados de teste
Crie o método
UseModelWithSingleItem()
, logo após o métodoEvaluate()
, usando o seguinte código:void UseModelWithSingleItem(MLContext mlContext, ITransformer model) { }
O método
UseModelWithSingleItem()
executa as seguintes tarefas:- Cria um único comentário dos dados de teste.
- Prevê o sentimento com base nos dados de teste.
- Combina dados de teste e previsões para relatórios.
- Exibe os resultados previstos.
Adicione uma chamada ao novo método logo abaixo da chamada do método
Evaluate()
usando o seguinte código:UseModelWithSingleItem(mlContext, model);
Adicione o seguinte código para criar a primeira linha no método
UseModelWithSingleItem()
:PredictionEngine<SentimentData, SentimentPrediction> predictionFunction = mlContext.Model.CreatePredictionEngine<SentimentData, SentimentPrediction>(model);
O PredictionEngine é uma API de conveniência, que permite executar uma previsão em uma instância individual de dados.
PredictionEngine
não é thread-safe. É aceitável usá-lo em ambientes de thread único ou de protótipo. Para aprimorar o desempenho e o acesso thread-safe em ambientes de produção, use o serviçoPredictionEnginePool
, que cria umObjectPool
de objetosPredictionEngine
para uso em todo o aplicativo. Confira este guia sobre como usar oPredictionEnginePool
em uma API Web ASP.NET Core.Observação
A extensão de serviço
PredictionEnginePool
está atualmente em versão prévia.Adicione um comentário para testar as previsões do modelo treinado no método
UseModelWithSingleItem()
ao criar uma instância deSentimentData
:SentimentData sampleStatement = new SentimentData { SentimentText = "This was a very bad steak" };
Passe os dados de comentário de teste para o
PredictionEngine
adicionando o seguinte como as próximas linhas do código no métodoUseModelWithSingleItem()
:var resultPrediction = predictionFunction.Predict(sampleStatement);
A função Predict() faz uma previsão em uma única coluna de dados.
Exiba
SentimentText
e a previsão de sentimento correspondente usando o código a seguir: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();
Usar o modelo para previsão
Implantar e prever itens em lotes
Crie o método
UseModelWithBatchItems()
, logo após o métodoUseModelWithSingleItem()
, usando o seguinte código:void UseModelWithBatchItems(MLContext mlContext, ITransformer model) { }
O método
UseModelWithBatchItems()
executa as seguintes tarefas:- Cria dados de teste em lote.
- Prevê o sentimento com base nos dados de teste.
- Combina dados de teste e previsões para relatórios.
- Exibe os resultados previstos.
Adicione uma chamada ao novo método logo abaixo da chamada do método
UseModelWithSingleItem()
usando o seguinte código:UseModelWithBatchItems(mlContext, model);
Adicione alguns comentários para testar as previsões do modelo treinado no método
UseModelWithBatchItems()
:IEnumerable<SentimentData> sentiments = new[] { new SentimentData { SentimentText = "This was a horrible meal" }, new SentimentData { SentimentText = "I love this spaghetti." } };
Prever sentimento de comentário
Use o modelo para prever o sentimento dos dados de comentários usando o 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);
Combinar e exibir as previsões
Crie um cabeçalho para as previsões usando o seguinte código:
Console.WriteLine();
Console.WriteLine("=============== Prediction Test of loaded model with multiple samples ===============");
Como SentimentPrediction
é herdado de SentimentData
, o método Transform()
preencheu SentimentText
com os campos previstos. Conforme o processo do ML.NET processa, cada componente adiciona colunas e isso facilita a exibição dos 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
Seus resultados devem ser semelhantes aos seguintes. Durante o processamento, as mensagens são exibidas. Você pode ver avisos ou mensagens de processamento. Eles foram removidos dos seguintes resultados para maior clareza.
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 . . .
Parabéns! Agora você criou com sucesso um modelo de aprendizado de máquina para classificar e prever o sentimento das mensagens.
A criação de modelos bem-sucedidos é um processo iterativo. Esse modelo tem qualidade inicial inferior, pois o tutorial usa conjuntos de dados pequenos para fornecer um treinamento rápido do modelo. Se você não estiver satisfeito com a qualidade do modelo, tente melhorá-lo fornecendo conjuntos de dados de treinamento maiores ou escolhendo diferentes algoritmos de treinamento com diferentes hiperparâmetros para cada algoritmo.
Você pode encontrar o código-fonte para este tutorial no repositório dotnet/samples.
Próximas etapas
Neste tutorial, você aprendeu a:
- Criar um aplicativo de console
- Preparar dados
- Carregar os dados
- Criar e treinar o modelo
- Avaliar o modelo
- Usar o modelo para fazer uma previsão
- Confira os resultados
Avançar para o próximo tutorial para saber mais