朴素Bayse新闻分类实践

目录

  • 1、信息增益(互信息)介绍
    • (1)西瓜书中的信息增益[^1]
    • (2)PRML中的互信息[^2]
    • (3) 其实他们是一个东西
  • 2、朴素Bayse新闻分类[^3]
    • (1)常量及辅助函数
    • (2)特征提取
    • (3)训练模型
    • (4)预测
    • (5)测试
    • (6)测试结果

1、信息增益(互信息)介绍

由于在最终的bayse算法中只使用了部分的特征,而特征的选择使用到了信息增益,所以在这里做一个简单的介绍。

(1)西瓜书中的信息增益1

在西瓜书的4.2节中,选择树节点的划分属性时提到了信息增益;其定义如下:
首先是元集合D的类别信息熵

Ent(D)=−∑k=1∣y∣pklog2(pk)Ent(D)=-\sum_{k=1}^{\left | y \right |}p_{k}log_{2}(p_{k}) Ent(D)=k=1ypklog2(pk)
然后根据属性a划分为了V个集合后,给出了信息增益的定义:
Gain(D,a)=Ent(D)−∑v=1V∣Dv∣∣D∣Ent(Dv)Gain(D, a)=Ent(D) - \sum_{v=1}^{V}\frac{\left | D^{v} \right |}{\left | D \right |}Ent(D^v) Gain(D,a)=Ent(D)v=1VDDvEnt(Dv)
然后利用信息增益来进行树的划分特征的选取。

(2)PRML中的互信息2

在PRML1.6.1中定义了互信息,公式如下:
I[x,y]≡KL(p(x,y)∣∣p(x)p(y))=−∬p(x,y)ln(p(x)p(y)p(x,y))dxdyI[x, y] \equiv KL(p(x, y)|| p(x)p(y)) = - \iint p(x,y)ln(\frac{p(x)p(y)}{p(x,y)}) dxdy I[x,y]KL(p(x,y)p(x)p(y))=p(x,y)ln(p(x,y)p(x)p(y))dxdy
化简后可以得到:
I[x,y]≡H[x]−H[x∣y]=H[y]−H[y∣x]I[x,y]\equiv H[x] - H[x|y] = H[y] - H[y|x] I[x,y]H[x]H[xy]=H[y]H[yx]

(3) 其实他们是一个东西

证明:首先把1、->(2)中的积分形式改写成和的形式,并把ln还成log(相差了log2倍),有
−∑x,yp(x,y)log2(p(x)p(y)p(x,y))-\sum_{x,y}p(x,y)log_{2}(\frac{p(x)p(y)}{p(x,y)})x,yp(x,y)log2(p(x,y)p(x)p(y))
=−∑y∑xp(x,y)log2(p(y))−(−∑xp(x)∑yp(y∣x)log2(p(y∣x)))= -\sum_{y}\sum_{x}p(x,y)log_{2}(p(y)) - (-\sum_{x}p(x)\sum_{y}p(y|x)log_{2}(p(y|x)))=yxp(x,y)log2(p(y))(xp(x)yp(yx)log2(p(yx)))
=−∑yp(y)log2(p(y))−(−∑xp(x)∑yp(y∣x)log2(p(y∣x)))=-\sum_{y}p(y)log_{2}(p(y))-(-\sum_{x}p(x)\sum_{y}p(y|x)log_{2}(p(y|x)))=yp(y)log2(p(y))(xp(x)yp(yx)log2(p(yx)))

仔细观察·是不是和1、->(1)一模一样!如下图所示:
互信息与信息增益的对比

2、朴素Bayse新闻分类3

(1)常量及辅助函数

import math
import random
import collections
label_dict = {0: '财经', 1: '健康', 2: '教育', 3: '军事', 4: '科技',5: '旅游', 6: '母婴', 7: '汽车', 8: '体育',9: '文化', 10: '娱乐'}def code_2_label(code):return label_dict.get(code)def default_doc_dict():"""构造和类别数等长的0向量:return: 一个长度和文档类别数相同的全0数组,用来作为某些以该长度数组为值的字典的默认返回值"""return [0] * len(label_dict)def shuffle(in_file):"""简单的乱序操作,用于生成训练集和测试集:param in_file: 输入文件:return:"""text_lines = [line.strip() for line in open(in_file, encoding='utf-8')]print('正在准备训练数据和测试数据,请稍后...')random.shuffle(text_lines)total_lines = len(text_lines)train_text = text_lines[:int(3 * total_lines / 5)]test_text = text_lines[int(3 * total_lines / 5):]print('准备训练数据和测试数据完毕,下一步...')return train_text, test_text

(2)特征提取

根据1中的信息增益(互信息)的大小来提取前100个最重要的特征(这里就是词了)
首先定义了如下的计算互信息的辅助函数,它所计算的内容其实是:
互信息辅助函数
(注意红色的-,我把它移到了和的内部)

def mutual_info(N, Nij, N_i, N_j):"""计算互信息,这里log的底取为2;同时为了防止Nij为0,分子做了+1的平滑:param N:总样本数:param Nij:x为i,y为j的样本数:param N_i:x为i的样本数:param N_j:y为j的样本数:return:"""return Nij * 1.0 / N * math.log(N * (Nij + 1) * 1.0 / (N_i * N_j)) / math.log(2)

看起来并不是很清晰,因为是化简以后的。这里进行一下推导:
−p(x=i,y=j)log2(p(x=i)p(y=j)p(x=i,y=j))-p(x=i,y=j)log_{2}(\frac{p(x=i)p(y=j)}{p(x=i,y=j)})p(x=i,y=j)log2(p(x=i,y=j)p(x=i)p(y=j))
=−Ni,jN∗log2(NiNNjNNi,jN)=-\frac{N_{i,j}}{N}*log_{2}(\frac{\frac{N_{i}}{N}\frac{N_{j}}{N}}{\frac{N_{i,j}}{N}})=NNi,jlog2(NNi,jNNiNNj)
=Ni,jN∗log2(NNi,jNiNj)=\frac{N_{i,j}}{N}*log_{2}(\frac{NN_{i,j}}{N_{i}N_{j}})=NNi,jlog2(NiNjNNi,j)
=Ni,jN∗ln(NNi,jNiNj)/ln(2)=\frac{N_{i,j}}{N}*ln(\frac{NN_{i,j}}{N_{i}N_{j}})/ln(2)=NNi,jln(NiNjNNi,j)/ln(2)
加上平滑以后,就得到了上面的函数(别在乎1.0,只是整数转浮点数)
=Ni,jN∗ln(N(Ni,j+1)NiNj)/ln(2)=\frac{N_{i,j}}{N}*ln(\frac{N(N_{i,j}+1)}{N_{i}N_{j}})/ln(2)=NNi,jln(NiNjN(Ni,j+1))/ln(2)

def count_for_cates(train_text, feature_file):"""遍历文件,统计每个词在每个类别中出现的次数,以及每个类别中的文档数,并将结果写入特征文件(只写互信息值最大的前100项):param train_text::param feature_file::return:"""# 各个类别中所包含的词的个数doc_count = [0] * len(label_dict)# 以word为key的字典,value是对应该word# 在每个类别中出现次数的向量;该词不存在就返回全0的向量word_count = collections.defaultdict(default_doc_dict)# 扫描文件和计数for line in train_text:label, text = line.strip().rstrip('\n').split(' ', 1)words = text.split(' ')int_label = int(label)for word in words:# 空字符串用了停用词也没有过滤掉,就在这里处理了if word != '':word_count[word][int_label] += 1doc_count[int_label] += 1# 计算互信息print('计算互信息,提取关键/特征词中,请稍后...')# 互信息结果字典,value描述的是某个类别中的词数# 衡量的信息量与明确是某个词以后的以词数衡量的信息量的互信息mi_dict = collections.defaultdict(default_doc_dict)# 词总量N = sum(doc_count)# (word,[...各个类别中该词出现的词数...])for k, vs in word_count.items():for i in range(len(vs)):# N11代表是词k并且出现在类别i中的词数N11 = vs[i]# N10 代表是词k但未出现在类别i中的词数N10 = sum(vs) - N11# N01 代表不是词k但出现在类别i中的词数N01 = doc_count[i] - N11# N00 代表不是词k也未出现在类别i中的词数N00 = N - N11 - N10 - N01"""设D为某个类别中的词总数,A为某个词出现的总次数,N为总词数则下面的式子表达的是mutual_info(N,DA,A,D) + mutual_info(N,~DA, A, ~D) + mutual_info(N,D~A, D, ~A) + mutual_info(N, ~D~A, ~D, ~A)"""mi = mutual_info(N, N11, N10 + N11, N01 + N11) + mutual_info(N, N10, N10 + N11, N00 + N10) + mutual_info(N, N01, N01 + N11, N01 + N00) + mutual_info(N, N00, N00 + N10, N00 + N01)mi_dict[k][i] = mi# 用来作为bayes参数的词f_words = set()# 把每类文档分类最重要的100个词放到f_words中for i in range(len(doc_count)):sorted_dict = sorted(mi_dict.items(), key=lambda x: x[1][i], reverse=True)for j in range(100):f_words.add(sorted_dict[j][0])with open(feature_file, 'w', encoding='utf-8') as out:# 输出每个类别中包含的词的数量out.write(str(doc_count) + '\n')# 输出作为参数的词for f_word in f_words:out.write(f_word + "\n")print("特征词写入完毕...")
def load_feature_words(feature_file):"""从特征文件中导入特征词:param feature_file::return:"""with open(feature_file, encoding='utf-8') as f:# 每个类别中包含的词的数量doc_words_count = eval(f.readline())features = set()# 读取特征词for line in f:features.add(line.strip())return doc_words_count, features

(3)训练模型

def train_bayes(feature_file, text, model_file):"""训练贝叶斯模型,实际上计算每个类别中特征词的出现次数:param feature_file: 特征文件:param text: 原始的样本:param model_file: 模型文件:return:"""print('使用朴素贝叶斯训练中...')doc_words_count, features = load_feature_words(feature_file)feature_word_count = collections.defaultdict(default_doc_dict)# 每类文档中特征词出现的总次数feature_doc_words_count = [0] * len(doc_words_count)for line in text:label, text = line.strip().rstrip('\n').split(' ', 1)int_label = int(label)words = text.split(' ')for word in words:if word in features:feature_doc_words_count[int_label] += 1feature_word_count[word][int_label] += 1out_model = open(model_file, 'w', encoding='utf-8')print('训练完毕,写入模型...')for k, v in feature_word_count.items():scores = [(v[i] + 1) * 1.0 / (feature_doc_words_count[i] + len(feature_word_count)) for i in range(len(v))]out_model.write(k + '\t' + str(scores) + '\n')
def load_model(model_file):"""从模型文件中导入计算好的贝叶斯模型:param model_file::return:"""print('加载模型中...')with open(model_file, encoding='utf-8') as f:scores = {}for line in f.readlines():word, counts = line.split('\t', 1)scores[word] = eval(counts)return scores

(4)预测

def predict(feature_file, model_file, test_text):"""预测文档的类别,标准输入每一行为一个文档这是一个朴素贝叶斯的预测方法p(c|x) 正比于 p(c)p(x1|c)....p(xn|c):param feature_file::param model_file::param test_text::return:"""doc_words_count, features = load_feature_words(feature_file)# p(c)doc_scores = [math.log(count * 1.0 / sum(doc_words_count)) for count in doc_words_count]scores = load_model(model_file)r_count = 0doc_count = 0print("正在使用测试数据验证模型效果...")for line in test_text:label, text = line.strip().split(' ', 1)int_label = int(label)words = text.split(' ')pre_values = list(doc_scores)for word in words:if word in features:for i in range(len(pre_values)):pre_values[i] += math.log(scores[word][i])m = max(pre_values)p_index = pre_values.index(m)if p_index == int_label:r_count += 1doc_count += 1print("总共测试文本量: %d ,预测正确的类别量:%d,朴素贝叶斯分类器准确度:%f" %(doc_count, r_count, r_count * 1.0 / doc_count))

(5)测试

if __name__ == '__main__':out_in_file = 'd:/nlps/result.txt'out_feature_file = 'd:/nlps/feature.txt'out_model_file = 'd:/nlps/model.txt'train_text, test_text = shuffle(out_in_file)count_for_cates(train_text, out_feature_file)train_bayes(out_feature_file, train_text, out_model_file)predict(out_feature_file, out_model_file, test_text)

(6)测试结果

运行结果


  1. 周志华 《机器学习》 4.2节 ↩︎

  2. Bishop “Pattern Recognition and Machine Learning” 1.6.1 ↩︎

  3. 寒小阳 ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/569140.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

R树空间索引及其变种

1、R树及其变种:百度百科 2、R树详介:http://blog.csdn.net/jazywoo123/article/details/7792745 3、R树及变种小结 R树:叶子节点或中间节点都可能有交集。衡量指标有查询性能和更新性能,更新通过删除和插入实现。R树:…

Kaggle-泰坦尼克号

目录前言和感谢正题前言和感谢 机器学习本人还是一个新手,现在处在练习阶段。在网上找到了很多免费的比较老旧kaggle比赛讲解的python代码,在这里自己亲在体验并跟着过了一遍。在运行的过程中加入了自己的一些改动并且修改了一些存在的BUG,同…

hdu 六度分离 floyd

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid1869 题意分析:比较简单的最短路算法,最后只需判断最远两点距离是否大于7即可。 /*六度分离Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tot…

Kaggle-自行车租赁人数预测

目录前言和感谢正题前言和感谢 机器学习本人还是一个新手,现在处在练习阶段。在网上找到了很多免费的比较老旧kaggle比赛讲解的python代码,在这里自己亲在体验并跟着过了一遍。在运行的过程中加入了自己的一些改动并且修改了一些存在的BUG,同…

【数据仓库】OLTP系统和OLAP系统区别

OLTP:联机事务处理系统(OnLine Transaction Processing) OLAP:联机分析处理系统(OnLine Analytical Processing) 参考文档: 操作数据库系统(OLTP)和联机分析处理系统(OLAP)的区别转载于:https://www.cnblogs.com/badboy200800/p/11189478.htm…

吴恩达深度学习编程作业汇总

以下列表为吴恩达的深度学习课程所对应的编程作业列表,都直接指向了github的连接地址;这些作业也是我在网上购买,可能与官方的内容有所出入;同时由于有的训练集和测试集以及预训练好的参数过大,不便上传,所…

Good Numbers(HDU5447+唯一分解)

题目链接 传送门 题面 题意 首先定义对于\(k\)的好数\(u\):如果\(u\leq k\)且\(u\)的所有质因子与\(k\)的质因子一样则称\(u\)对于\(k\)是一个好数。 现给你两个数\(k1,k2(1\leq k1,k2\leq 10^{24})\),要你求\(k1,k2\)的好数个数,对于\(k1,k2…

从机器码到面向对象

1.从机器码到面向对象 本章节主要探讨是什么驱动着编程从机器码发展到了汇编语言,又从汇编语言发展到了面向过程编程,最后从面向过程编程发展到面向对象编程。通过这些探讨最终明确多年来的软件工程发展我们都解决了哪些棘手的问题。 1.1机器码 在真正…

【MySQL】JavaWeb项目中配置数据库的连接池

在META-INF目录下新建context.xml <?xml version"1.0" encoding"UTF-8"?> <Context><Resource name"jdbc/TestDB" auth"Container" type"javax.sql.DataSource"maxActive"10" maxIdle"4&qu…

面向对象那么好,为什么贫血模型如此流行?

2.面向对象那么好&#xff0c;为什么贫血模型如此流行&#xff1f; 2.1我们身边真的没有面向对象吗&#xff1f; 我们总是在强调我们的身边都是贫血模型&#xff0c;但是当我们仔细观察我们所引用的jar包时&#xff0c;我们会惊讶地发现&#xff0c;原来面向对象开发一直在我…

spfa_队列

spfa:1.当给定的图存在负权边时&#xff0c;Dijkstra等算法便没有了用武之地&#xff0c;而Bellman-Ford算法的复杂度又过高&#xff0c;SPFA算法便派上用场了.2.我们约定有向加权图G不存在负权回路&#xff0c;即最短路径一定存在3.思路&#xff1a;用数组d记录每个结点的最短…

Tomcat配置解析

Tomcat文件配置 tomcat解压后目录 bin&#xff1a;可执行文件&#xff08;startup.bat shutdown.bat) conf&#xff1a;配置文件&#xff08;server.xml&#xff09; lib&#xff1a;tomcat依赖的jar文件 log&#xff1a;日志文件&#xff08;记录出错等信息&#xff09; temp&…

教你配置安全的ProFTPD服务器(中)

二、 基本加固ProFTPD服务器步骤 1.升级版本 注&#xff1a;如果当前版本已经是最新版本&#xff0c;可以跳过第一步。 升级陈旧的ProFTPD版本&#xff0c;因为早期的ProFTPD版本存在的安全漏洞。对于一个新配置的ProFTPD服务器来说使用最新稳定版本是最明智的选择&#xff0c;…

前端动画 wow.js 效果

让花里胡哨的特效变简单 wow.js动画class介绍 引入css样式以及js插件 <link rel"stylesheet" type"text/css" href"./css/animate.min.css"><script src"./js/wow.min.js"></script><script> new WOW().init(…

Clob类型转换为String

SQL CLOB 是内置类型&#xff0c;它将字符大对象存储为数据库表某一行中的一个列值&#xff0c;使用CHAR来存储数据&#xff0c;如XML文档。 如下是一个Clob转换为String的静态方法&#xff0c;可将其放在自己常用的工具类中&#xff0c;想直接用的话&#xff0c;自己稍作修改即…

Java 将Word转为PDF、PNG、SVG、RTF、XPS、TXT、XML

同一文档在不同的编译或阅读环境中&#xff0c;需要使用特定的文档格式来打开&#xff0c;通常需要通过转换文档格式的方式来实现。下面将介绍在Java程序中如何来转换Word文档为其他几种常见文档格式&#xff0c;如PDF、图片png、svg、xps、rtf、txt、xml等。 使用工具&#xf…

CentOS7上GitLab的使用

生成SSH Keys 生成root账号的ssh key # ssh-keygen -t rsa -C "adminexample.com" 显示pub key的值 # cat ~/.ssh/id_rsa.pub 复制显示出来的 pub key 以root账号登陆gitlab&#xff0c;点击 "profile settings" 然后点击 "SSH Keys" 将复制的pu…

数据与计算机通信复习重点

数据与计算机通信讲义 第一次课 网络概论 自我介绍 主要承担网络方向课程教学&#xff1a;计算机网络、网络程序设计等 负责课程设计、工程实训等实践教学组织&#xff1a;程序设计基础实训、OS课设、程序设计综合实训 课程安排 课程性质 理论课46学时&#xff0c;限选、考试、…

数据库:除运算

除运算 设关系R除以关系S的结果为关系T&#xff0c;则T包含所有在R但不在S中的属性及其值&#xff0c;则T的原则与S的元组的所有组合都在R中。用象集来定义除法&#xff1a;给定关系R&#xff08;X&#xff0c;Y&#xff09;和S&#xff08;Y&#xff0c;Z&#xff09;。其中X&…

[图解tensorflow源码] 入门准备工作附常用的矩阵计算工具[转]

[图解tensorflow源码] 入门准备工作附常用的矩阵计算工具[转] Link: https://www.cnblogs.com/yao62995/p/5773142.html tensorflow使用了自动化构建工具bazel、脚本语言调用c或cpp的包裹工具swig、使用EIGEN作为矩阵处理工具、Nvidia-cuBLAS GPU加速计算库、结构化数据存储格式…