教程:在 ML.NET 中使用二元分类分析网站评论的情绪
本教程演示如何创建 .NET Core 控制台应用程序,该应用程序对网站评论情绪进行分类并采取适当的措施。 二元情绪分类器在 Visual Studio 2022 中使用 C#。
在本教程中,你将了解:
- 创建控制台应用程序
- 准备数据
- 加载数据
- 生成和定型模型
- 评估模型
- 使用模型进行预测
- 查看结果
可以在 dotnet/samples 存储库中找到本教程的源代码。
先决条件
创建控制台应用程序
创建名为“SentimentAnalysis”的 C# 控制台应用程序。 单击“下一步”按钮。
选择 .NET 6 作为要使用的框架。 单击“创建” 按钮。
在项目中创建名为“Data”的目录,用于保存数据集文件。
安装“Microsoft.ML NuGet 包” :
注意
除非另有说明,否则本示例使用前面提到的 NuGet 包的最新稳定版本。
在“解决方案资源管理器”中,右键单击项目,然后选择“管理 NuGet 包” 。 选择“nuget.org”作为包源,然后选择“浏览”选项卡。搜索“Microsoft.ML”,选择所需的包,然后选择“安装”按钮 。 同意所选包的许可条款,继续执行安装。
准备数据
注意
本教程的数据集摘自 KDD 2015 中由 Kotzias 等提出的“From Group to Individual Labels using Deep Features”, 并托管在 UCI 机器学习存储库中(Dua, D. 和 Karra Taniskidou, E.(2017))。 UCI 机器学习存储库 [http://archive.ics.uci.edu/ml ]。 加利福尼亚州,加利福尼亚大学:欧文分校,信息与计算机科学学院。
将
yelp_labelled.txt
文件复制到已创建的“Data”目录中。在“解决方案资源管理器”中,右键单击
yelp_labeled.txt
文件并选择“属性”。 在“高级”下,将“复制到输出目录”的值更改为“如果较新则复制” 。
创建类和定义路径
将以下附加的
using
语句添加到“Program.cs”文件顶部:using Microsoft.ML; using Microsoft.ML.Data; using SentimentAnalysis; using static Microsoft.ML.DataOperationsCatalog;
将以下代码添加到
using
语句正下方的行中,以创建字段来保存最近下载的数据集文件路径:string _dataPath = Path.Combine(Environment.CurrentDirectory, "Data", "yelp_labelled.txt");
接下来,为输入数据和预测结果创建类。 向项目添加一个新类:
在“解决方案资源管理器” 中,右键单击项目,然后选择“添加” >“新项” 。
在“添加新项” 对话框中,选择“类” 并将“名称” 字段更改为“SentimentData.cs” 。 然后,选择“添加”按钮。
“SentimentData.cs” 文件随即在代码编辑器中打开。 将下面的
using
语句添加到 SentimentData.cs 的顶部:using Microsoft.ML.Data;
删除现有类定义并向“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
拥有一个用于用户评论 (SentimentText
) 的 string
,以及一个用于情绪的 bool
(Sentiment
),值为 1(正面)或 0(负面)。 这两个字段都附加了 LoadColumn 特性,其描述了每个字段的数据文件顺序。 此外,Sentiment
属性具有 ColumnName 特性,以将其指定为 Label
字段。 下面的示例文件没有标题行,如下所示:
情绪文本 | 情绪(标签) |
---|---|
女服务员的服务速度有点慢。 | 0 |
酥皮不行。 | 0 |
哇...喜欢这个地方。 | 1 |
服务很及时。 | 1 |
SentimentPrediction
是在模型训练后使用的预测类。 它继承自 SentimentData
,因此输入 SentimentText
可与输出预测结果一并显示。 Prediction
布尔值是随附新的输入 SentimentText
提供时模型预测出的值。
输出类 SentimentPrediction
包含另外两个由模型计算得出的属性:Score
(模型计算得出的原始分数)和 Probability
(校准到具有积极情绪的文本几率的分数)。
在本教程中,最重要的属性是 Prediction
。
加载数据
ML.NET 中的数据表示为 IDataView 接口。 IDataView
是用于描述表格数据(数字和文本)的一种灵活且有效的方法。 可从文本文件或实时(例如,SQL 数据库或日志文件)将数据加载到 IDataView
对象。
MLContext 类是所有 ML.NET 操作的起点。 初始化 mlContext
会创建一个新的 ML.NET 环境,可在模型创建工作流对象之间共享该环境。 从概念上讲,它与实体框架中的 DBContext
类似。
准备应用,然后加载数据:
使用以下代码替换
Console.WriteLine("Hello World!")
行,以声明和初始化 mlContext 变量:MLContext mlContext = new MLContext();
将以下代码作为下一行代码:
TrainTestData splitDataView = LoadData(mlContext);
使用以下代码在
Program.cs
文件底部创建LoadData()
方法:TrainTestData LoadData(MLContext mlContext) { }
LoadData()
方法执行以下任务:- 加载数据。
- 将加载的数据集拆分为训练数据集和测试数据集。
- 返回拆分的训练数据集和测试数据集。
将以下代码添加为
LoadData()
方法的首行:IDataView dataView = mlContext.Data.LoadFromTextFile<SentimentData>(_dataPath, hasHeader: false);
LoadFromTextFile() 方法用于定义数据架构并读取文件。 它使用数据路径变量并返回
IDataView
。
拆分数据集以进行模型训练和测试
准备模型时,使用部分数据集来训练它,并使用部分数据集来测试模型的准确性。
要将加载的数据拆分为所需的数据集,请添加以下代码作为
LoadData()
方法中的下一行:TrainTestData splitDataView = mlContext.Data.TrainTestSplit(dataView, testFraction: 0.2);
上述代码使用 TrainTestSplit() 方法将加载的数据集拆分为训练数据集和测试数据集,并在 DataOperationsCatalog.TrainTestData 类中返回它们。 使用
testFraction
参数指定数据的测试集百分比。 默认值为 10%,在本例中使用 20%,以评估更多数据。在
LoadData()
方法末尾返回splitDataView
:return splitDataView;
生成和定型模型
在对
LoadData
方法的调用下方添加对BuildAndTrainModel
方法的以下调用:ITransformer model = BuildAndTrainModel(mlContext, splitDataView.TrainSet);
BuildAndTrainModel()
方法执行以下任务:- 提取并转换数据。
- 定型模型。
- 根据测试数据预测情绪。
- 返回模型。
使用以下代码在
LoadData()
方法下方创建BuildAndTrainModel()
方法:ITransformer BuildAndTrainModel(MLContext mlContext, IDataView splitTrainSet) { }
提取和转换数据
将
FeaturizeText
作为下一行代码调用:var estimator = mlContext.Transforms.Text.FeaturizeText(outputColumnName: "Features", inputColumnName: nameof(SentimentData.SentimentText))
上述代码中的
FeaturizeText()
方法将文本列 (SentimentText
) 转换为机器学习算法使用的数字键类型的Features
列,并将其作为新的数据集列添加:情绪文本 情绪 特征 女服务员的服务速度有点慢。 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
输入参数,以便从历史数据中学习。
定型模型
在 BuildAndTrainModel()
方法中添加以下代码作为下一代码行,使模型适应 splitTrainSet
数据,并返回经过训练的模型:
Console.WriteLine("=============== Create and Train the Model ===============");
var model = estimator.Fit(splitTrainSet);
Console.WriteLine("=============== End of training ===============");
Console.WriteLine();
Fit() 方法通过转换数据集并应用训练来训练模型。
返回定型模型以用于评估
在 BuildAndTrainModel()
方法末尾返回模型:
return model;
评估模型
训练模型后,使用测试数据验证模型的性能。
使用以下代码紧跟
BuildAndTrainModel()
之后创建Evaluate()
方法:void Evaluate(MLContext mlContext, ITransformer model, IDataView splitTestSet) { }
Evaluate()
方法执行以下任务:- 加载测试数据集。
- 创建 BinaryClassification 计算器。
- 评估模型并创建指标。
- 显示指标。
使用以下代码在
BuildAndTrainModel
方法调用下方添加对新方法的调用:Evaluate(mlContext, model, splitDataView.TestSet);
将以下代码添加到
Evaluate()
以转换splitTestSet
数据:Console.WriteLine("=============== Evaluating Model accuracy with Test data==============="); IDataView predictions = model.Transform(splitTestSet);
之前的代码使用 Transform() 方法对测试数据集提供的多个输入行进行预测。
通过在
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
尽可能接近 1。F1Score
指标可获取模型的 F1 分数,该分数是查准率和查全率之间的平衡关系的度量值。 应该使F1Score
尽可能接近 1。
预测测试数据结果
使用下面的代码紧随
Evaluate()
方法后创建UseModelWithSingleItem()
方法:void UseModelWithSingleItem(MLContext mlContext, ITransformer model) { }
UseModelWithSingleItem()
方法执行以下任务:- 创建测试数据的单个注释。
- 根据测试数据预测情绪。
- 结合测试数据和预测进行报告。
- 显示预测结果。
使用以下代码在
Evaluate()
方法调用的正下方添加对新方法的调用:UseModelWithSingleItem(mlContext, model);
添加以下代码,以便作为
UseModelWithSingleItem()
方法中的第一行进行创建:PredictionEngine<SentimentData, SentimentPrediction> predictionFunction = mlContext.Model.CreatePredictionEngine<SentimentData, SentimentPrediction>(model);
PredictionEngine 是一个简便 API,可使用它对单个数据实例执行预测。
PredictionEngine
不是线程安全。 可以在单线程环境或原型环境中使用。 为了在生产环境中提高性能和线程安全,请使用PredictionEnginePool
服务,这将创建一个在整个应用程序中使用的PredictionEngine
对象的ObjectPool
。 请参阅本指南,了解如何在 ASP.NET Core Web API 中使用PredictionEnginePool
。注意
PredictionEnginePool
服务扩展目前处于预览状态。通过创建一个
SentimentData
实例,在UseModelWithSingleItem()
方法中添加一个注释来测试定型模型的预测:SentimentData sampleStatement = new SentimentData { SentimentText = "This was a very bad steak" };
通过在
UseModelWithSingleItem()
方法中将以下代码作为下一行代码添加,将测试评论数据传递到PredictionEngine
:var resultPrediction = predictionFunction.Predict(sampleStatement);
Predict() 函数对单行数据进行预测。
使用以下代码显示
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();
使用模型进行预测
部署和预测批项目
使用下面的代码紧随
UseModelWithSingleItem()
方法后创建UseModelWithBatchItems()
方法:void UseModelWithBatchItems(MLContext mlContext, ITransformer model) { }
UseModelWithBatchItems()
方法执行以下任务:- 创建批处理测试数据。
- 根据测试数据预测情绪。
- 结合测试数据和预测进行报告。
- 显示预测结果。
使用以下代码在
UseModelWithSingleItem()
方法调用的正下方添加对新方法的调用:UseModelWithBatchItems(mlContext, model);
添加一些评论,以测试
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 存储库中找到本教程的源代码。
后续步骤
在本教程中,你将了解:
- 创建控制台应用程序
- 准备数据
- 加载数据
- 生成和定型模型
- 评估模型
- 使用模型进行预测
- 查看结果
进入下一教程了解详细信息