这篇文章做了什么

不先介绍点基础?

朴素贝叶斯,真的很朴素

情感分析是啥

朴素贝叶斯如何实现情感分析

1.前期准备:

做好正负面标记的文本作为训练集

正负面词库

2.针对文本实现:

分词,推荐使用Jieba分词引擎,无论是python, C#, 还是R语言上都有非常优秀的第三方库,而且可以导入词库

获取正负面词,此时需要用到正负面词库,即通过正负面词库的匹配,筛选出文本中能够反映情感的词。

进入训练集中匹配,获取每个正面或者负面的词在两个训练集的词频,如“好吃”这个词在正面训练集里出现频率为0.1%,而在负面训练集里频率为0.001%。

通过贝叶斯公式计算出在文本出现“好吃”这个词的条件下位正面或者为负面的概率,例如:

$p(正面|"好吃") = \frac{p(正面)p("好吃"|正面)}{p(正面)p("好吃"|正面)+ p(负面)p("好吃"|负面)} $

得到的概率即是在好吃这个词出现的条件下,该句子为正面的概率。

然而一句话可能有多个表示情感的词,比如"不好看"、"开心",我们最终要求得在这些词出现的条件下该文本为正面的条件概率:\(p(正面|"好吃","不好看","开心")\),具体计算过程见如下推导,令上述三个词分别为a,b,c,正面为pos,负面为neg:

\[\begin{eqnarray}

p(pos|a,b,c) &=& \frac{p(pos)p(a,b,c|pos)}{p(pos)p(a,b,c|pos)+p(neg)p(a,b,c|neg)}\\\\

&=& \frac{p(pos)p(a|pos)p(b|pos)p(c|pos)}{p(pos)p(a|pos)p(b|pos)p(c|pos)+p(neg)p(a|neg)p(b|neg)p(c|neg)}

\end{eqnarray}

\]

假设一句话为正面或是负面的先验概率均为0.5,则\(p(pos) = p(neg) = 0.5\),那么(2)式等于:

\[\begin{eqnarray}

= \frac{p(a|pos)p(b|pos)p(c|pos)}{p(a|pos)p(b|pos)p(c|pos) + p(a|neg)p(b|neg)p(c|neg)}

\end{eqnarray}

\]

拉普拉斯平滑:为了避免某个词在训练集中出现概率为0导致结果有偏,拉普拉斯平滑法讲所有词出现次数加一,在样本量很大时,每个分量加一几乎不会对最终估计结果造成太大影响,但这样的好处是很好的解决了词频为0导致的有偏问题。

其他变式

贝叶斯推断及其互联网应用(二):过滤垃圾邮件这篇文章中做了如下变形,将结果以单个词下正面或是负面的条件概率表示,但是文章并未提及拉普拉斯校准,而是用拍脑袋想出来的1%作为校准概率。由于:

\[\begin{eqnarray}

p(a|pos)& =& \frac{p(a|pos)p(a)}{p(a)}\\\\

&=& \frac{p(a|pos)p(a)}{p(a|pos)p(pos)+p(a|neg)p(neg)} (全概率公式)\\\\

&=& \frac{p(a|pos)p(pos)}{p(a|pos)p(pos)+p(a|neg)p(neg)}p(a)/p(pos)\\\\

&=& \frac{p(pos|a)p(a)}{p(pos)}\\\\

\end{eqnarray}

\]

所以有(3)式等于:

\[\begin{eqnarray}

(3)式& =& \frac{\frac{p(pos|a)p(pos|b)p(pos|c)p(a)p(b)p(c)}{p(pos)^3}}{\frac{p(pos|a)p(pos|b)p(pos|c)p(a)p(b)p(c)}{p(pos)^3} + \frac{p(neg|a)p(neg|b)p(neg|c)p(a)p(b)p(c)}{p(neg)^3}}\\\\

&=& \frac{p(pos|a)p(pos|b)p(pos|c)}{p(pos|a)p(pos|b)p(pos|c)+p(neg|a)p(neg|b)p(neg|c)}\\\\

&=& \frac{p(pos|a)p(pos|b)p(pos|c)}{p(pos|a)p(pos|b)p(pos|c)+(1-p(pos|a))(1-p(pos|b))(1-p(pos|c))}\\\\

\end{eqnarray}

\]

以上公式均为自己推导,作者原文中并未详细写出,如涉及侵权问题请通知我删除此部分。如有问题也欢迎大家指出,谢谢~。

3.聊一聊其他的

python号称最强大的中文自然语言处理库SnowNLP,其中的情感分析事实上非常粗糙,首先它并没有一个正负面的词库,而是把一个句子分出的所有词都参与计算,包括各种各样的无意义词、符号等等,而事实上这些词并不能反映任何情感。作者可能先验的认为正负面训练集中这些无情感词频率可以认为是近似的,但事实并非如此,所以这些词将导致计算结果有偏。

缺点:

朴素贝叶斯假设每个词是独立的,但是事实并非如此,尤其是针对长篇文章,或者是出现多个复杂语气词情况,独立性假设失效。

无法处理句子中比较的情况,无法落在句子中某一个产品或者属性上,难以做意见挖掘。

依赖于高质量的语料库

优点:

无需对句子成分进行分解,无需分析语法语义

针对无法判断正负面的词时有效(“呵呵”,“卧槽”等)

正负面词混杂时,依旧可以根据训练集做出较为准确的判断

说了这么多,我该如何实现呢?

在此小弟附上c#代码,如果觉得不清晰,您可以移步至我的GitHub:

//首先需要加载Jieba.Net,可以通过NuGet自行安装,然后using

//建立jieba类,用以处理训练集和文本

class Jieba

{

public string doc{get;set;}

public string PosWords {get;set;}

public string NegWords {get;set;}

public string stopwords {get;set;}

public List JiebaCut()

{

JiebaSegmenter jiebaseg = new JiebaSegmenter();

var segment = jiebaseg.Cut(doc);

List cutresult = new List();

foreach (var i in segment)

{

if (!stopwords.Contains(i))

cutresult.Add(i);

}

return cutresult;

}

public List handle_sentiment(bool pos = true)

{

var words = JiebaCut();

string PosOrNegWords = pos ? PosWords:NegWords;

List handle_result = new List();

foreach (var word in words)

{

if (PosOrNegWords.Contains(word))

handle_result.Add(word);

}

return handle_result;

}

public List handle_words()

{

var words = JiebaCut();

List handle_result = new List();

foreach (var word in words)

{

if ((PosWords + NegWords).Contains(word))

handle_result.Add(word);

}

return handle_result;

}

}

然后,我们需要定义一个处理概率的类,以及派生类

class BaseProb

{

public Dictionary d = new Dictionary();

public double total = 0.0;

public int none = 0;

public bool exists(string key) { return d.Keys.Contains(key); }

public double getsum() { return total; }

public void get(string key, out bool para1, out double para2)

{

if (!exists(key))

{

para1 = false; para2 = none;

}

else

{

para1 = true;para2 = d[key];

}

}

public double freq(string key)

{

bool para1;

double para2;

get(key, out para1, out para2);

return para2 / total;

}

//def samples(self):

// return self.d.keys()

}

class AddOneProb : BaseProb

{

//public Dictionary d = new Dictionary();

//public double total = 0.0;

//public int none = 1;

public void add(string key, int value)

{

total += value;

if (!exists(key))

{

d.Add(key, 1);

total += 1;

}

d[key] += value;

}

public void DPrint()

{

Console.WriteLine(d.Count);

Console.ReadKey();

foreach (var key in d.Keys)

{

Console.WriteLine(key+" : "+d[key].ToString());

}

}

}

接下来需要将原始训练集序列化为Json格式,方便以后调用,我使用的是LitJson,转为["pos":{"我是一个词":10},"neg":{"我也是一个词":20}]的形式,以后直接读取词频而非整个句子再进行分词与统计。我们通过以下代码读取序列化后的数据:

public static Dictionary Load(string filepath, out double total)

{

string json;

using (var sr = new StreamReader(filepath, Encoding.Default))

json = sr.ReadToEnd();

JsonData jd = JsonMapper.ToObject(json);

Dictionary d = new Dictionary() { { "neg", new AddOneProb() }, { "pos", new AddOneProb() } };

foreach (var i in jd["d"]["neg"]["d"])

{

var arr = i.ToString().Replace("[","").Replace("]","").Split(',');

int count = 0;

if (int.TryParse(arr[1],out count ))

d["neg"].add(arr[0], count);

}

foreach (var i in jd["d"]["pos"]["d"])

{

var arr = i.ToString().Replace("[", "").Replace("]", "").Split(',');

int count = 0;

if (int.TryParse(arr[1], out count))

d["pos"].add(arr[0], count);

}

total = Convert.ToDouble (jd["total"].ToString());

return d;

}

当然如果你不想进行序列化,也行,可以通过以下代码训练样本

public static void Train_data(string negFilePath, string negWords, string posFilePath, string posWords,

ref Dictionary d, ref double total, string stopwordFilepath)

{

//d = new Dictionary() { { "pos", new AddOneProb() }, { "neg", new AddOneProb() } };

string negfile = "", posfile = "";

using (var sr1 = new StreamReader(negFilePath, Encoding.Default))

negfile = sr1.ReadToEnd();

using (var sr2 = new StreamReader(posFilePath, Encoding.Default))

posfile = sr2.ReadToEnd();

string stopwords = ReadTxtToEnd(stopwordFilepath);

List, string>> data = new List, string>>();

var sent_cut = new Jieba();

sent_cut.NegWords = negWords;

sent_cut.PosWords = posWords;

foreach (var sent in posfile.Replace("\r", "").Split('\n'))

{

sent_cut.doc = sent;

sent_cut.stopwords = stopwords;

data.Add(new Tuple, string>(sent_cut.handle_sentiment(), "pos"));

}

Console.WriteLine("正面词库导入完毕");

foreach (var sent in negfile.Replace("\r", "").Split('\n'))

{

sent_cut.doc = sent;

sent_cut.stopwords = stopwords;

data.Add(new Tuple, string>(sent_cut.handle_sentiment(false), "neg"));

}

Console.WriteLine("负面词库导入完毕");

foreach (var d_ in data)

{

var c = d_.Item2.ToString();

if (d_.Item1 == null)

continue;

else

{

foreach (var word in d_.Item1)

d[c].add(word, 1);

}

}

total = 0;

foreach (var value in d.Values)

{

total += value.total;

}

}

接下来就可以写分类函数了,是这样的:

protected static Tuple Classify(List x,

Dictionary d, double total)

{

Dictionary temp = new Dictionary();

foreach (var k in d.Keys)

{

temp.Add(k, Math.Log(0.5));

foreach (var word in x)

{

Console.WriteLine(k+" : "+word + " : " + d[k].freq(word));

temp[k] += Math.Log(d[k].freq(word));

}

Console.ReadKey();

}

string ret = "";

double prob = 0;

double now;

foreach (var k in d.Keys)

{

now = 0;

foreach (var otherk in d.Keys)

{

try

{

now += Math.Exp(temp[otherk] - temp[k]);

}

catch (Exception)

{

now = 10000;

}

}

now = 1 / now;

if (now > prob)

{

ret = k;

prob = now;

}

}

return new Tuple(ret, prob);

}

public static double classify_(string sent, Dictionary d,

double total, string stopwordFilepath)

{

Jieba jiebaword = new Jieba();

jiebaword.doc = sent;

jiebaword.stopwords = ReadTxtToEnd(stopwordFilepath);

var retprob = Classify(jiebaword.JiebaCut(), d, total);

if (retprob.Item1 == "pos")

return retprob.Item2;

else

return 1 - retprob.Item2;

}

如何使用:

static void Main(string[] args)

{

double total = 0;

var d = Train.Load(SentimentFilepath + "sentiment_json.txt",out total);

var poswords = Train.ReadTxtToEnd(SentimentFilepath + "pos.csv");

var negwords = Train.ReadTxtToEnd(SentimentFilepath + "neg.csv");

Train.Train_data(SentimentFilepath + "neg_train.csv", negwords, SentimentFilepath + "pos_train.csv", poswords,ref d, ref total, SentimentFilepath + "stopwords.csv");

string testsentence = "很忽悠,不好";

var sent = Train.classify_(testsentence, d, total, SentimentFilepath + "stopwords.csv");

Console.WriteLine(sent);

Console.ReadKey();

}

本博原创作品仅供品读,欢迎评论,未经本人同意谢绝转载。特此申明!

朴素贝叶斯情感分析评分python_朴素贝叶斯算法下的情感分析——C#编程实现相关推荐

  1. 朴素贝叶斯情感分析评分python_比朴素贝叶斯更优秀的情感分析方法?答案在这里...

    作者|Samuel Pilcer 译者 & 编辑|Debra AI 前线导读:根据在线评论和评分,我们可以为客户提供关于其信誉度的深刻见解.我们会拆解评论文本了解评论的内容,并告诉我们的客户他 ...

  2. 朴素贝叶斯情感分析评分python_「豆瓣影评」从爬取豆瓣影评到基于朴素贝叶斯的电影评论情感分析(上) - seo实验室...

    豆瓣影评 一.爬取豆瓣影评 基本思路:先获取每个电影的评论区链接,然后依次进入其评论区爬取评论.选取10部电影,每部200条评论. 用到的包为:BeautifulSoup,urllib 这里选取的链接 ...

  3. 朴素贝叶斯情感分析评分python_详解基于朴素贝叶斯的情感分析及 Python 实现

    相对于「 基于词典的分析 」,「 基于机器学习 」的就不需要大量标注的词典,但是需要大量标记的数据,比如: 还是下面这句话,如果它的标签是: 服务质量 - 中 (共有三个级别,好.中.差) �r(�s ...

  4. 朴素贝叶斯情感分析评分python_详解基于朴素贝叶斯的情感分析及Python实现

    朴素贝叶斯 1.贝叶斯定理 假设对于某个数据集,随机变量C表示样本为C类的概率,F1表示测试样本某特征出现的概率,套用基本贝叶斯公式,则如下所示: 上式表示对于某个样本,特征F1出现时,该样本被分为C ...

  5. 朴素贝叶斯情感分析评分python_Stanford NLP学习笔记:7. 情感分析(Sentiment)

    1. 什么是情感分析(别名:观点提取,主题分析,情感挖掘...) 应用: 1)正面VS负面的影评(影片分类问题) 2)产品/品牌评价: Google产品搜索 3)twitter情感预测股票市场行情/消 ...

  6. 实现 | 朴素贝叶斯模型算法研究与实例分析

    实现 | 朴素贝叶斯模型算法研究与实例分析 (白宁超  2018年9月4日10:28:49) 导读:朴素贝叶斯模型是机器学习常用的模型算法之一,其在文本分类方面简单易行,且取得不错的分类效果.所以很受 ...

  7. [深度学习-NLP]Imdb数据集情感分析之模型对比(贝叶斯, LSTM, GRU, TextCNN, Transformer, BERT)

    一,详细原理以及代码请看下面博客 1.Imdb数据集情感分析之离散贝叶斯 2.Imdb数据集情感分析之LSTM长短期记忆 3.Imdb数据集情感分析之卷积神经网络-TextCNN 4.Imdb数据集情 ...

  8. 【阿旭机器学习实战】【10】朴素贝叶斯模型原理及3种贝叶斯模型对比:高斯分布朴素贝叶斯、多项式分布朴素贝叶斯、伯努利分布朴素贝叶斯

    [阿旭机器学习实战]系列文章主要介绍机器学习的各种算法模型及其实战案例,欢迎点赞,关注共同学习交流. 本文介绍了机器学习中的朴素贝叶斯的基本原理,并对3种贝叶斯模型根据鸢尾花实例进行了比较. 目录 朴 ...

  9. 机器学习之朴素贝叶斯(一):朴素贝叶斯的介绍、概率基础(拉普拉斯平滑)、sklearn朴素贝叶斯实现API、朴素贝叶斯分类的优缺点、文本的特征工程

    朴素贝叶斯 文章目录 朴素贝叶斯 一.介绍 1.1 文本分类的应用 词云的例子 垃圾邮件分类 文章类别的概率 二.概率基础 2.1 概率例题 2.2 联合概率和条件概率 2.3 朴素贝叶斯-贝叶斯公式 ...

最新文章

  1. liunx检查与安装软件包
  2. swap 将硬盘变内存
  3. spring3依赖包下载
  4. Prosjecni(构造)
  5. Robolectric 探索之路
  6. java mongo 日期范围_获取指定日期和它之前几天,之间的所有日期?千万不要踩了这个大坑!...
  7. KL 散度(从动力系统到推荐系统)
  8. Linux 备份与恢复
  9. Python绘制心形图案
  10. CVPR 2021 论文大盘点-医学影像篇
  11. 古剑奇谭2打砺罂10分钟过的方法!
  12. 利用Django框架简单设计一个登陆页面
  13. 鼠标经过图片 图片放大缩小
  14. (使用工具)Matlab转C++
  15. [从头学数学] 第46节 数学广角──集合
  16. oracle突然变慢 awr,AWR收集缓慢、挂起的几种常见情况分析
  17. redis6种数据淘汰策略
  18. WebAssembly js性能对比
  19. 孤狼电商店群全套教程:店群基础+2.0精细化蓝海+深度蓝海+裂变课程2.0
  20. 迷你服务器开机无显示,迷你版云服务器未启动

热门文章

  1. 让我们一起为宝宝选绘本(怎么给宝宝挑选绘本,看完本文就够了)
  2. 光遇服务器修复暴风眼刷新了吗,光遇暴风眼怎么进 光遇暴风眼刷新时间
  3. 基于FPGA的视频图像拼接融合(附源码)。
  4. 十七点学完安全知识超级详细了解进程和病毒知识 转载
  5. jsp页面转为html5,eclipse 设置jsp页面为HTML5
  6. H5实现win10日历效果
  7. 手机录制连续点赞并周期执行(免代码)
  8. spark union 会引起shuffle吗_Spark高性能Job
  9. 五金与机械行业的WMS系统方案
  10. Word2019单个页面显示多个文件