使用ML.NET实现情感分析[新手篇]
在发出《.NET Core玩转机器学习》和《使用ML.NET预测纽约出租车费》两文后,相信读者朋友们即使在不明就里的情况下,也能按照内容顺利跑完代码运行出结果,对使用.NET Core和ML.NET,以及机器学习的效果有了初步感知。得到这些体验后,那么就需要回头小结一下了,本文仍然基于一个情感分析的案例,以刚接触机器学习的.NET开发者的视角,侧重展开一下起手ML.NET的基本理解和步骤。
当我们意识到某个现实问题超出了传统的模式匹配能力范围,需要借助模拟的方式先尽可能还原已经产生的事实(通常也称为拟合),然后复用这种稳定的模拟过程(通常也称为模型),对即将发生的条件进行估计,求得发生或不发生相同结果的概率,此时就是利用机器学习最好的机会,同时也要看到,这也是机器学习通常离不开大量数据的原因,历史数据太少,模拟还原这个过程效果就会差很多,自然地,评估的结果误差就大了。所以在重视数据的准确性、完整性的同时,要学会经营数据的体量出来。
若要使用机器学习解决问题,一般会经历以下这些步骤:
1. 描述问题产生的场景
2. 针对特定场景收集数据
3. 对数据预处理
4. 确定模型(算法)进行训练
5. 对训练好的模型进行验证和调优
6. 使用模型进行预测分析
接下来我将用案例逐一介绍。
描述问题产生的场景
说到情感分析,我假定一个最简单的句子表达的场景,就是当看到一句话,通过特定的词语,我们能判断这是一个正向积极的态度,或是负面消极的。比如“我的程序顺利通过测试啦”这就是一个正向的,而“这个函数的性能实在堪忧”就是一个负面的表达。所以,对词语的鉴别就能间接知道说这句话的人的情感反应。(本案例为降低理解的复杂程度,暂不考虑断句、重音、标点之类的这些因素。)
针对特定场景收集数据
为了证实上面的思路,我们需要先收集一些有用的数据。其实这也是让众多开发者卡住的环节,除了使用爬虫和自己系统中的历史数据,往往想不到短时间还能在哪获取到。互联网上有不少学院和机构,甚至政府都是有开放数据集提供的,推荐两处获取比较高质量数据集的来源:
UC Irvine Machine Learning Repository来自加州大学
kaggle.com一个著名的计算科学与机器学习竞赛网站
这次我从UCI找到一个刚好只是每行有一个句子加一个标签,并且标签已标注好每个句子是正向还是负向的数据集了。在Sentiment Labelled Sentences Data Set下载。格式类似如下:
A very, very, very slow-moving, aimless movie about a distressed, drifting young man. 0
Not sure who was more lost - the flat characters or the audience, nearly half of whom walked out. 0
Attempting artiness with black & white and clever camera angles, the movie disappointed - became even more ridiculous - as the acting was poor and the plot and lines almost non-existent. 0
Very little music or anything to speak of. 0
The best scene in the movie was when Gerardo is trying to find a song that keeps running through his head. 1
The rest of the movie lacks art, charm, meaning... If it's about emptiness, it works I guess because it's empty. 0
Wasted two hours. 0
...
观察每一行,一共是Tab分隔的两个字段,第一个字段是句子,一般我们称之为特征(Feature),第二个字段是个数值,0表示负向,1表示正向,一般我们称之为目标或标签(Label),目标值往往是人工标注的,如果没有这个,是无法使用对历史数据进行拟合这种机器学习方式的。所以,一份高质量的数据集对人工标注的要求很高,要尽可能准确。
对数据预处理
对于创建项目一系列步骤,参看我开头提到的两篇文章即可,不再赘述。我们直接进入正题,ML.NET对数据的处理以及后面的训练流程是通用的,这也是为了以后扩展到其他第三方机器学习包设计的。首先观察数据集的格式,创建与数据集一致的结构,方便导入过程。LearningPipeline类专门用来定义机器学习过程的对象,所以紧接着我们需要创建它。代码如下:
const string _dataPath = @".\data\sentiment labelled sentences\imdb_labelled.txt";
const string _testDataPath = @".\data\sentiment labelled sentences\yelp_labelled.txt"; public class SentimentData
{
[Column(ordinal: "")]
public string SentimentText;
[Column(ordinal: "", name: "Label")]
public float Sentiment;
} var pipeline = new LearningPipeline();
pipeline.Add(new TextLoader<SentimentData>(_dataPath, useHeader: false, separator: "tab"));
pipeline.Add(new TextFeaturizer("Features", "SentimentText"));
SentimentData就是我需要的导入用的数据结构,可以看到,Column属性除了指示对应数据集的行位置,额外的对应最后一列,表示正向还是负向的字段,还要指定它是目标值,并取了个标识名。TextLoader就是专门用来导入文本数据的类,TextFeaturizer就是指定特征的类,因为每一行数据不是每一个字段都可以成为特征的,如果有较多字段时,可以在此处特别地指定出来,这样不会被无关的字段影响。
确定模型(算法)进行训练
本案例目标是一个0/1的值类型,换句话说恰好是一个二分类问题,因此模型上我选择了FastTreeBinaryClassifier这个类,如果略有了解机器学习的朋友一定知道逻辑回归算法,与之在目的上大致相似。若要定义模型,同时要指定一个预测用的结构,这样模型就会按特定的结构输出模型的效果,一般这个输出用的结构至少要包含目标字段。代码片段如下:
public class SentimentPrediction
{
[ColumnName("PredictedLabel")]
public bool Sentiment;
} pipeline.Add(new FastTreeBinaryClassifier() { NumLeaves = , NumTrees = , MinDocumentsInLeafs = }); PredictionModel<SentimentData, SentimentPrediction> model = pipeline.Train<SentimentData, SentimentPrediction>();
对训练好的模型进行验证和调优
在得到模型后,需要用测试数据集进行验证,看看拟合的效果是不是符合预期,BinaryClassificationEvaluator就是FastTreeBinaryClassifier对应的验证用的类,验证的结果用BinaryClassificationMetrics类保存。代码片段如下:
var testData = new TextLoader<SentimentData>(_testDataPath, useHeader: false, separator: "tab");
var evaluator = new BinaryClassificationEvaluator();
BinaryClassificationMetrics metrics = evaluator.Evaluate(model, testData);
Console.WriteLine();
Console.WriteLine("PredictionModel quality metrics evaluation");
Console.WriteLine("------------------------------------------");
Console.WriteLine($"Accuracy: {metrics.Accuracy:P2}");
Console.WriteLine($"Auc: {metrics.Auc:P2}");
Console.WriteLine($"F1Score: {metrics.F1Score:P2}");
像Accuracy,Auc,F1Score都是一些常见的评价指标,包含了正确率、误差一类的得分,如果得分很低,就需要调整前一个步骤中定义模型时的参数值。详细的解释参考:Machine learning glossary
使用模型进行预测分析
训练好一个称心如意的模型后,就可以正式使用了。本质上就是再取来一些没有人工标注结果的数据,让模型进行分析返回一个符合某目标值的概率。代码片段如下:
IEnumerable<SentimentData> sentiments = new[]
{
new SentimentData
{
SentimentText = "Contoso's 11 is a wonderful experience",
Sentiment =
},
new SentimentData
{
SentimentText = "The acting in this movie is very bad",
Sentiment =
},
new SentimentData
{
SentimentText = "Joe versus the Volcano Coffee Company is a great film.",
Sentiment =
}
};
IEnumerable<SentimentPrediction> predictions = model.Predict(sentiments);
Console.WriteLine();
Console.WriteLine("Sentiment Predictions");
Console.WriteLine("---------------------"); var sentimentsAndPredictions = sentiments.Zip(predictions, (sentiment, prediction) => (sentiment, prediction));
foreach (var item in sentimentsAndPredictions)
{
Console.WriteLine($"Sentiment: {item.sentiment.SentimentText} | Prediction: {(item.prediction.Sentiment ? "Positive" : "Negative")}");
}
运行结果可以看到,其分类是符合真实判断的。尽管验证阶段的得分不高,这也是很正常的,再没有任何调优下,存在一些中性、多义的句子干扰预测导致的。

这样,再有新的句子就可以放心地通过程序自动完成分类了,是不是很简单!希望本文能带给.NET开发的朋友们对ML.NET跃跃欲试的兴趣。
顺便提一下,微软Azure还有一个机器学习的在线工作室,链接地址为:https://studio.azureml.net/,相关的AI项目库在:https://gallery.azure.ai/browse,对于暂时无法安装本地机器学习环境,以及找不到练手项目的朋友 ,不妨试试这个。
最后放出项目的文件结构以及完整的代码:

using System;
using Microsoft.ML.Models;
using Microsoft.ML.Runtime;
using Microsoft.ML.Runtime.Api;
using Microsoft.ML.Trainers;
using Microsoft.ML.Transforms;
using System.Collections.Generic;
using System.Linq;
using Microsoft.ML; namespace SentimentAnalysis
{
class Program
{
const string _dataPath = @".\data\sentiment labelled sentences\imdb_labelled.txt";
const string _testDataPath = @".\data\sentiment labelled sentences\yelp_labelled.txt"; public class SentimentData
{
[Column(ordinal: "")]
public string SentimentText;
[Column(ordinal: "", name: "Label")]
public float Sentiment;
} public class SentimentPrediction
{
[ColumnName("PredictedLabel")]
public bool Sentiment;
} public static PredictionModel<SentimentData, SentimentPrediction> Train()
{
var pipeline = new LearningPipeline();
pipeline.Add(new TextLoader<SentimentData>(_dataPath, useHeader: false, separator: "tab"));
pipeline.Add(new TextFeaturizer("Features", "SentimentText"));
pipeline.Add(new FastTreeBinaryClassifier() { NumLeaves = , NumTrees = , MinDocumentsInLeafs = }); PredictionModel<SentimentData, SentimentPrediction> model = pipeline.Train<SentimentData, SentimentPrediction>();
return model;
} public static void Evaluate(PredictionModel<SentimentData, SentimentPrediction> model)
{
var testData = new TextLoader<SentimentData>(_testDataPath, useHeader: false, separator: "tab");
var evaluator = new BinaryClassificationEvaluator();
BinaryClassificationMetrics metrics = evaluator.Evaluate(model, testData);
Console.WriteLine();
Console.WriteLine("PredictionModel quality metrics evaluation");
Console.WriteLine("------------------------------------------");
Console.WriteLine($"Accuracy: {metrics.Accuracy:P2}");
Console.WriteLine($"Auc: {metrics.Auc:P2}");
Console.WriteLine($"F1Score: {metrics.F1Score:P2}");
} public static void Predict(PredictionModel<SentimentData, SentimentPrediction> model)
{
IEnumerable<SentimentData> sentiments = new[]
{
new SentimentData
{
SentimentText = "Contoso's 11 is a wonderful experience",
Sentiment =
},
new SentimentData
{
SentimentText = "The acting in this movie is very bad",
Sentiment =
},
new SentimentData
{
SentimentText = "Joe versus the Volcano Coffee Company is a great film.",
Sentiment =
}
};
IEnumerable<SentimentPrediction> predictions = model.Predict(sentiments);
Console.WriteLine();
Console.WriteLine("Sentiment Predictions");
Console.WriteLine("---------------------"); var sentimentsAndPredictions = sentiments.Zip(predictions, (sentiment, prediction) => (sentiment, prediction));
foreach (var item in sentimentsAndPredictions)
{
Console.WriteLine($"Sentiment: {item.sentiment.SentimentText} | Prediction: {(item.prediction.Sentiment ? "Positive" : "Negative")}");
}
Console.WriteLine();
} static void Main(string[] args)
{
var model = Train();
Evaluate(model);
Predict(model);
}
}
}
使用ML.NET实现情感分析[新手篇]的更多相关文章
- 使用ML.NET实现情感分析[新手篇]后补
在<使用ML.NET实现情感分析[新手篇]>完成后,有热心的朋友建议说,为何例子不用中文的呢,其实大家是需要知道怎么预处理中文的数据集的.想想确实有道理,于是略微调整一些代码,权作示范. ...
- INTERSPEECH2020 语音情感分析论文之我见
摘要:本文为大家带来InterSpeech2020 语音情感分析25篇论文中的其中8篇的总结. 本文分享自华为云社区<INTERSPEECH2020 语音情感分析论文总结一>,原文作者:T ...
- Python爬虫和情感分析简介
摘要 这篇短文的目的是分享我这几天里从头开始学习Python爬虫技术的经验,并展示对爬取的文本进行情感分析(文本分类)的一些挖掘结果. 不同于其他专注爬虫技术的介绍,这里首先阐述爬取网络数据动机,接着 ...
- 在Keras中用Bert进行情感分析
之前在BERT实战——基于Keras一文中介绍了两个库 keras_bert 和 bert4keras 但是由于 bert4keras 处于开发阶段,有些函数名称和位置等等发生了变化,那篇文章只用了 ...
- 如何用KNIME进行情感分析
Customer Intelligence Social Media Finance Credit Scoring Manufacturing Pharma / Health Care Retail ...
- 朴素贝叶斯算法下的情感分析——C#编程实现
这篇文章做了什么 朴素贝叶斯算法是机器学习中非常重要的分类算法,用途十分广泛,如垃圾邮件处理等.而情感分析(Sentiment Analysis)是自然语言处理(Natural Language Pr ...
- Stanford NLP学习笔记:7. 情感分析(Sentiment)
1. 什么是情感分析(别名:观点提取,主题分析,情感挖掘...) 应用: 1)正面VS负面的影评(影片分类问题) 2)产品/品牌评价: Google产品搜索 3)twitter情感预测股票市场行情/消 ...
- SA: 情感分析资源(Corpus、Dictionary)
先主要摘自一篇中文Survey,http://wenku.baidu.com/view/0c33af946bec0975f465e277.html 4.2 情感分析的资源建设 4.2.1 情感分析 ...
- C#编程实现朴素贝叶斯算法下的情感分析
C#编程实现 这篇文章做了什么 朴素贝叶斯算法是机器学习中非常重要的分类算法,用途十分广泛,如垃圾邮件处理等.而情感分析(Sentiment Analysis)是自然语言处理(Natural Lang ...
随机推荐
- 业务线接入前端异常监控sentry
1.前端异常处理的框架对比 是否开源 收费 语言 监控范围 sentry 是 自己搭建服务器(免费)价格 英文 Angular.AngularJs.Backbone.Ember.JavaScrip ...
- PBRT笔记(13)——光线传播1:表面反射
采样反射函数 BxDF::Sample_f()方法根据与相应的散射函数相似的分布来选择方向.在8.2节中,该方法用于寻找来自完美镜面的反射和透射光线;在这里讲介绍实现其他类型的采样技术. BxDF:: ...
- Spring Cloud项目MVN编译 -- Non-resolvable import POM
最近利用闲余时间,打算搭建一套基于Spring Cloud G版的微服务架构(Spring boot 2.1.0),一顿操作之后,IDEA也没有提示什么错误,自认为微服务搭建完毕.启动项目前,习惯性的 ...
- wordcount源代码详解
package wordcount; import java.io.IOException; import java.util.StringTokenizer; import org.apache.h ...
- sqlalchemy 使用
创建连接 # 参数: '数据库类型+数据库驱动名称://用户名:口令@机器地址:端口号/数据库名' from sqlalchemy import create_engine engine = crea ...
- Linux 下redis 集群搭建练习
Redis集群 学习参考:https://blog.csdn.net/jeffleo/article/details/54848428https://my.oschina.net/iyinghui/b ...
- HTML/CSS实现的一个列表页
又到休息日,白天没事跟朋友去逛逛街,侃大山,晚上了,上网无趣,于是就想起该练练了, 这次是做了一个页面,最上面是一个banner 用到了一个jQuery的逻辑判断当banner初始top值小于wind ...
- ios开发中的深拷贝和浅拷贝
这是一个老生常谈的话题,面试中也经常被问到,下面总结一下自己的一些心得. 一句话总结: 浅拷贝就是指针拷贝: 深拷贝是对象本身的拷贝: 下面一张抽象的图可以直观的表述出两句话的内涵 其实这里还引申出了 ...
- SPA 单页面应用程序。
看到这个问题,先说下自己的理解到的程度,再去参考做修正,争取这一次弄懂搞清楚 自己的理解: 单页面应用程序,解决浏览器获取数据刷新页面的尴尬,通过ajax请求获取数据达到异步更新视图的按钮,原理的实现 ...
- 【高并发架构】Redis缓存高并发之-主从架构
Redis主从架构 到目前为止,Redis Cluster 能实现很好的性能,但如果只是缓存几个G的数据,那么单机Redis就足够了,但缓存主要用来读的,单机的QPS有一定的极限,一两万QPS一台应该 ...