朴素贝叶斯(Naive Bayes)
朴素贝叶斯模型是基于概率论的原理,它的思想是这样的:对于给出的未知物体想要进行分类,就需要求解在这个未知物体出现的条件下各个类别出现的概率,哪个最大,就认为这个未知物体属于哪个分类
比如,如果你看到一个人总是花钱,那么会推断这个人多半是个有钱人。当然这也不是绝对
也就是说,当你不能准确预知一个事物本质的时候,你可以依靠和事物本质相关的事件来进行判断,如果事情发生的频次多,则证明这个属性更有可能存在
假设有一种病叫做“贝叶死”,它的发病率是万分之一,即10000人中会有1个人得病
现有一种测试可以检验一个人是否得病的准确率是99.9%,它的误报率是0.1%
那么现在的问题是,如果一个人被查出来患有“叶贝死”,实际上患有的可能性有多大?
你可能会想说,既然查出患有“贝叶死”的准确率是99.9%,那是不是实际上患“贝叶死”的概率也是99.9%呢?
实际上不是的,在10000个人中,还存在0.1%的误查的情况,也就是10个人没有患病但是被诊断成阳性
当然10000个人中,也确实存在一个患有贝叶死的人,他有99.9%的概率被检查出来
所以可以粗算下,患病的这个人实际上是这11个人里面的一员,即实际患病比例是1/11≈9%
上面这个例子中,实际上涉及到了贝叶斯原理中的几个概念:
先验概率
通过经验来判断事情发生的概率,比如说“贝叶死”的发病率是万分之一,就是先验概率
再比如南方的梅雨季是6-7月,就是通过往年的气候总结出来的经验,这个时候下雨的概率就比其他时间高出很多
后验概率
后验概率就是发生结果之后,推测原因的概率
比如说某人查出来了患有“贝叶死”,那么患病的原因可能是A、B或C
患有“贝叶死”是因为原因A的概率就是后验概率。它是属于条件概率的一种
条件概率
事件A在另外一个事件B已经发生条件下的发生概率,表示为P(A|B),读作“在B发生的条件下A发生的概率”
比如原因A的条件下,患有“贝叶死”的概率,就是条件概率
似然函数(likelihood function)
你可以把概率模型的训练过程理解为求参数估计的过程
如果一个硬币在10次抛落中正面均朝上。那么你肯定在想,这个硬币是均匀的可能性是多少?
这里硬币均匀就是个参数,似然函数就是用来衡量这个模型的参数。似然在这里就是可能性的意思,它是关于统计参数的函数
介绍完贝叶斯原理中的这几个概念,我们再来看下贝叶斯原理,实际上贝叶斯原理就是求解后验概率
我们假设:A表示事件“测出为阳性”,用B1表示“患有贝叶死”,B2表示“没有患贝叶死”
根据上面那道题,我们可以得到下面的信息。患有贝叶死的情况下,测出为阳性的概率为P(A|B1)=99.9%
没有患贝叶死,但测出为阳性的概率为P(A|B2)=0.1%
另外患有贝叶死的概率为P(B1)=0.01%,没有患贝叶死的概率P(B2)=99.99%
那么我们检测出来为阳性,而且是贝叶死的概率P(B1,A) = P(B1) * P(A|B1) = 0.01% * 99.9% = 0.00999%
这里P(B1,A)代表的是联合概率,同样我们可以求得P(B2,A) = P(B2) * P(A|B2) = 99.99% * 0.1% = 0.09999%
然后我们想求得是检查为阳性的情况下,患有贝叶死的概率,也即是P(B1|A)
所以检查出阳性,且患有贝叶死的概率为:P(B1|A) = 0.01% / (0.01%+0.1%) ≈ 9%
所以检查出阳性,且没有患贝叶死的概率为:P(B2|A) = 0.1% / (0.01%+0.1%) ≈ 90.9%
这里我们能看出来0.01% + 0.1%均出现在了P(B1|A)和P(B2|A)的计算中作为分母
我们把它称之为论据因子,也相当于一个权值因子。其中P(B1)、P(B2)就是先验概率
我们现在知道了观测值,就是被检测出来是阳性,来求患贝叶死的概率,也就是求后验概率
求后验概率就是贝叶斯原理要求的,基于刚才求得的P(B1|A),P(B2|A),我们可以总结出贝叶斯公式为:
P(Bi|A) = P(Bi) * P(A|Bi) / (P(B1) * P(A|B1) + P(B2) * P(A|B2)) -> P(Bi|A) = P(Bi) * P(A|Bi) / ∑P(Bi) * P(A|Bi)
朴素贝叶斯
它是一种简单但极为强大的预测建模算法。之所以称为朴素贝叶斯,是因为它假设每个输入变量是独立的
这是一个强硬的假设,实际情况并不一定,但是这项技术对于绝大部分的复杂问题仍然非常有效
朴素贝叶斯模型由两种类型的概率组成:每个类别的概率P(Cj);每个属性的条件概率P(Ai|Cj)
假设有7个棋子,其中3个是白色的,4个是黑色的。那么棋子是白色的概率就是3/7,黑色的概率就是4/7,这个就是类别概率
假设把这7个棋子放到了两个盒子里,其中盒子A里面有2个白棋,2个黑棋,盒子B里面有1个白棋,2个黑棋
那么在盒子A中抓到白棋的概率就是1/2,抓到黑棋的概率也是1/2,这个就是条件概率,也就是在某个条件(比如在盒子A中)下的概率
在朴素贝叶斯中,我们要统计的是属性的条件概率,也就是假设取出来的是白色的棋子,那么它属于盒子A的概率是2/3
假设A代表白棋子,B1代表A盒,B2代表B盒。代入贝叶斯公式,我们可以得到:
P(B1|A) = P(B1)P(A|B1) / (P(B1)P(A|B1) + P(B2)P(A|B2)) = (4/7 * 1/2) / (4/7 * 1/2 + 3/7 * 1/3) = 2/3
为了训练朴素贝叶斯模型,我们需要先给出训练数据,以及这些数据对应的分类,那么上面这两个概率,也就是类别概率和条件概率
他们都可以从给出的训练数据中计算出来。一旦计算出来,概率模型就可以使用贝叶斯原理对新数据进行预测
贝叶斯原理、贝叶斯分类和朴素贝叶斯
贝叶斯原理是最大的概念,它解决了概率论中“逆向概率”的问题,在这个理论基础上,人们设计出了贝叶斯分类器
朴素贝叶斯分类是贝叶斯分类器中的一种,也是最简单,最常用的分类器
朴素贝叶斯之所以朴素是因为它假设属性是相互独立的,因此对实际情况有所约束
如果属性之间存在关联,分类准确率会降低。不过好在对于大部分情况下,朴素贝叶斯的分类效果都不错
朴素贝叶斯分类工作原理
我们日常生活中看到一个陌生人,要做的第一件事情就是判断TA的性别,判断性别的过程就是一个分类的过程
根据以往的经验,我们通常会从身高、体重、鞋码、头发长短、服饰、声音等角度进行判断
这里的“经验”就是一个训练好的关于性别判断的模型,其训练数据是日常中遇到的各式各样的人,以及这些人实际的性别数据
离散数据案例
我们遇到的数据可以分为两种,一种是离散数据,另一种是连续数据
那什么是离散数据呢?离散就是不连续的意思,有明确的边界,比如整数1,2,3就是离散数据
而1到3之间的任何数,就是连续数据,它可以取在这个区间里的任何数值
根据如下示例数据,推测:身高"高"、体重"中"、鞋码"中"的这个人是男是女?
编号 | 身高 | 体重 | 鞋码 | 性别 |
---|---|---|---|---|
1 | 高 | 重 | 大 | 男 |
2 | 高 | 重 | 大 | 男 |
3 | 中 | 中 | 大 | 男 |
4 | 中 | 中 | 中 | 男 |
5 | 矮 | 轻 | 小 | 女 |
6 | 矮 | 轻 | 小 | 女 |
7 | 矮 | 中 | 中 | 女 |
8 | 中 | 中 | 中 | 女 |
针对这个问题,我们先确定一共有3个属性,假设我们用A代表属性,用A1,A2,A3分别为身高=高、体重=中、鞋码=中。一共有两个类别,假设用C代表类别,那么C1,C2分别是:男、女,在未知的情况下我们用Cj表示
那么我们想求在A1、A2、A3属性下,Cj的概率,用条件概率表示就是P(Cj|A1A2A3)。根据上面讲的贝叶斯的公式,我们可以得出:
因为一共有2个类别,所以我们只需要求得P(C1|A1A2A3)和P(C2|A1A2A3)的概率即可,然后比较下哪个分类的可能性大,就是哪个分类结果
在这个公式里,因为P(A1A2A3)都是固定的,我们想要寻找使得P(Cj|A1A2A3)的最大值,就等价于求P(A1A2A3|Cj)P(Cj)最大值
我们假定Ai之间是相互独立的,那么:
P(A1A2A3|Cj)=P(A1|Cj)P(A2|Cj)P(A3|Cj)
然后我们需要从Ai和Cj中计算出P(Ai|Cj)的概率,代入上面的公式得出P(A1A2A3|Cj),最后找到使得P(A1A2A3|Cj)最大的类别Cj
分别求下这些条件下的概率:
- P(A1|C1)=1/2
- P(A2|C1)=1/2
- P(A3|C1)=1/4
- P(A1|C2)=0
- P(A2|C2)=1/2
- P(A3|C2)=1/2
所以,P(A1A2A3|C1)=1/16,P(A1A2A3|C2)=0
因为,P(A1A2A3|C1)P(C1) > P(A1A2A3|C2)P(C2)
所以应该是C1类别,即男性
连续数据案例
我们做了一个离散的数据案例,实际生活中我们得到的是连续的数值,比如下面这组数据:
编号 | 身高(CM) | 体重(斤) | 鞋码(欧码) | 性别 |
---|---|---|---|---|
1 | 183 | 164 | 45 | 男 |
2 | 182 | 170 | 44 | 男 |
3 | 178 | 160 | 43 | 男 |
4 | 175 | 140 | 40 | 男 |
5 | 160 | 88 | 35 | 女 |
6 | 165 | 100 | 37 | 女 |
7 | 163 | 110 | 38 | 女 |
8 | 168 | 120 | 39 | 女 |
那么如果给你一个新的数据,身高180、体重120,鞋码41,请问该人是男是女呢?
公式还是上面的公式,这里的困难在于,由于身高、体重、鞋码都是连续变量,不能采用离散变量的方法计算概率。而且由于样本太少,所以也无法分成区间计算
这时,可以假设男性和女性的身高、体重、鞋码都是正态分布,通过样本计算出均值和方差,也就是得到正态分布的密度函数。有了密度函数,就可以把值代入,算出某一点的密度函数的值
比如,男性的身高是均值179.5、标准差为3.697的正态分布。所以男性的身高为180的概率为0.1069
用EXCEL的NORMDIST(x,mean,standard_dev,cumulative)函数计算所得,一共有4个参数
- x:正态分布中,需要计算的数值
- Mean:正态分布的平均值
- Standard_dev:正态分布的标准差
- Cumulative:取值为逻辑值,即True或False。它决定了函数的形式。当为TRUE时,函数结果为累积分布;为False时,函数结果为概率密度
同理我们可以计算得出男性体重为120的概率为0.000382324,男性鞋码为41号的概率为0.120304111
所以我们可以计算得出:
P(A1A2A3|C1) = P(A1|C1)P(A2|C1)P(A3|C1) = 0.1069 * 0.000382324 * 0.120304111 = 4.9169e-6
同理我们也可以计算出来该人为女的可能性:
P(A1A2A3|C2) = P(A1|C2)P(A2|C2)P(A3|C2) = 0.00000147489 * 0.015354144 * 0.120306074 = 2.7244e-9
很明显这组数据分类为男的概率大于分类为女的概率
朴素贝叶斯分类器工作流程
朴素贝叶斯分类常用于文本分类,尤其是对于英文等语言来说,分类效果很好
它常用于垃圾文本过滤、情感预测、推荐系统、自然语言处理NLP的工具等
朴素贝叶斯分类器需要三个流程,如下图:
- 准备阶段
- 在这个阶段我们需要确定特征属性,比如上面案例中的“身高”、“体重”、“鞋码”等,并对每个特征属性进行适当划分,然后由人工对一部分数据进行分类,形成训练样本
- 这一阶段是整个朴素贝叶斯分类中唯一需要人工完成的阶段,其质量对整个过程将有重要影响,分类器的质量很大程度上由特征属性、特征属性划分及训练样本质量决定
- 训练阶段
- 这个阶段就是生成分类器,主要工作是计算每个类别在训练样本中的出现频率及每个特征属性划分对每个类别的条件概率
- 输入是特征属性和训练样本,输出是分类器
- 应用阶段
- 这个阶段是使用分类器对新数据进行分类。输入是分类器和新数据,输出是新数据的分类结果
Scikit-learn机器学习包
- 高斯朴素贝叶斯(GaussianNB):特征变量是连续变量,符合正态分布(高斯分布),比如说人的身高,物体的长度
- 多项式朴素贝叶斯(MultinomialNB):特征变量是离散变量,符合多项分布,在文档分类中特征变量体现在一个单词出现的次数,或者是单词的TF-IDF值等
- 多项式朴素贝叶斯是以单词为粒度,会计算在某个文件中的具体次数
- 伯努利朴素贝叶斯(BernoulliNB):特征变量是布尔变量,符合0/1分布,在文档分类中特征是单词是否出现
- 伯努利朴素贝叶斯是以文件为粒度,如果该单词在某文件中出现了即为1,否则为0
什么是TF-IDF值
TF-IDF是一个统计方法,用来评估某个词语对于一个文件集或文档库中的其中一份文件的重要程度
TF-IDF实际上是两个词组Term Frequency(词频)和Inverse Document Frequency(逆向文档频率)的总称
词频TF计算了一个单词在文档中出现的次数,它认为一个单词的重要性和它在文档中出现的次数呈正比
逆向文档频率IDF,是指一个单词在文档中的区分度。它认为一个单词出现在的文档数越少,就越能通过这个单词把该文档和其他文档区分开。IDF越大就代表该单词的区分度越大
所以TF-IDF实际上是词频TF和逆向文档频率IDF的乘积。这样我们倾向于找到TF和IDF取值都高的单词作为区分,即这个单词在一个文档中出现的次数多,同时又很少出现在其他文档中。这样的单词适合用于分类
TF-IDF如何计算
首先我们看下词频TF和逆向文档概率IDF的公式
为什么IDF的分母中,单词出现的文档数要加1呢?因为有些单词可能不会存在文档中,为了避免分母为0,统一给单词出现的文档数都加1
假设一个文件夹里一共有10篇文档,其中一篇文档有1000个单词,“this”这个单词出现20次,“bayes”出现了5次。“this”在所有文档中均出现过,而“bayes”只在2篇文档中出现过。我们来计算一下这两个词语的TF-IDF值
针对“this”,计算TF-IDF值:
所以TF-IDF = 0.02 * (-0.0414) = -8.28e-4
针对“bayes”,计算TF-IDF值:
TF-IDF = 0.005 * 0.5229 = 2.61e-3
很明显“bayes”的TF-IDF值要大于“this”的TF-IDF值。这就说明用“bayes”这个单词做区分比单词“this”要好
Scikit-learn求TF-IDF
在sklearn中我们直接使用TfidfVectorizer类,它可以帮我们计算单词TF-IDF向量的值。在这个类中,取sklearn计算的对数log时,底数是e,不是10
创建TfidfVectorizer
'''
stop_words:停用词,List类型
token_pattern:规律规则,正则表达式
'''
TfidfVectorizer(stop_words=stop_words, token_pattern=token_pattern)
什么是停用词?停用词就是在分类中没有用的词,这些词一般词频TF高,但是IDF很低,起不到分类的作用
为了节省空间和计算时间,我们把这些词作为停用词stopwords,告诉机器这些词不需要帮我计算
当我们创建好TF-IDF向量类型时,可以用fit_transform帮我们计算,返回给我们文本矩阵,该矩阵表示了每个单词在每个文档中的TF-IDF值
在我们进行fit_transform拟合模型后,我们可以得到更多的TF-IDF向量属性,比如,我们可以得到词汇的对应关系(字典类型)和向量的IDF值,当然也可以获取设置的停用词stop_words
- vocabulary_:词汇表,字典型
- idf_:返回idf值
- stopwords:返回停用词表
假设我们有4个文档,现在想要计算文档里都有哪些单词,这些单词在不同文档中的TF-IDF值是多少呢
from sklearn.feature_extraction.text import TfidfVectorizer
# 创建 TfidfVectorizer 类
tfidf_vec = TfidfVectorizer()
# 定义4个文档
documents = [
'this is the bayes document',
'this is the second second document',
'and the third one',
'is this the document'
]
# 对文档进行拟合,得到TF-IDF矩阵
tfidf_matrix = tfidf_vec.fit_transform(documents)
# 输出文档中所有不重复的词
print('不重复的词:', tfidf_vec.get_feature_names())
# 输出每个单词对应的id值
print('每个单词的ID:', tfidf_vec.vocabulary_)
# 输出每个单词在每个文档中的TF-IDF值,向量里的顺序是按照词语的id顺序来的(参照get_feature_names()的顺序)
# 这里计算出来的tfidf值与上面公式计算出来的值不同,因为经过了标准化处理,可以在构造函数中进行相应的参数设置
print('每个单词的tfidf值:', tfidf_matrix.toarray())
其他计算TF-IDF的库
from nltk import word_tokenize
from nltk import TextCollection
sents=['I love GuoGuo','I want to eat a watermelon','I am her father']
# 分词
sents=[word_tokenize(sent) for sent in sents]
# 构建语料库
corpus=TextCollection(sents)
# 计算TF
tf=corpus.tf('watermelon',corpus)
# 计算IDF
idf=corpus.idf('watermelon')
# 计算任意一个单词的TF-IDF
tf_idf=corpus.tf_idf('watermelon',corpus)
如何对文档进行分类
如果我们要对文档进行分类,有两个重要的阶段
- 基于分词的数据准备,包括分词、单词权重计算、去掉停用词
- 应用朴素贝叶斯分类进行分类,首先通过训练集得到朴素贝叶斯分类器,然后将分类器应用于测试集,并与实际结果做对比,最终得到测试集的分类准确率
对文档进行分词
在准备阶段里,最重要的就是分词。英文文档和中文文档所使用的分词工具不同
在英文文档中,最常用的是NTLK包。NTLK包中包含了英文的停用词stop words、分词和标注方法
import nltk
text = 'Hello world'
word_list = nltk.word_tokenize(text) # 分词
nltk.pos_tag(word_list) # 标注单词的词性
在中文文档中,最常用的是jieba包。jieba包中包含了中文的停用词stop words和分词方法
import jieba
text = "你好世界"
word_list = jieba.cut(text) # 中文分词
加载停用词表
网上可以找到中文常用的停用词,保存到stop_words.txt,然后利用Python的文件读取函数读取文件,保存在stop_words数组中
stop_words = [line.strip().decode('utf-8') for line in io.open('stop_words.txt').readlines()]
计算单词的权重
直接创建TfidfVectorizer类,然后使用fit_transform方法进行拟合,得到TF-IDF特征空间features
你可以理解为选出来的分词就是特征。我们计算这些特征在文档上的特征向量,得到特征空间features
from sklearn.feature_extraction.text import TfidfVectorizer
tf = TfidfVectorizer(stop_words=stop_words, max_df=0.5)
features = tf.fit_transform(train_contents)
这里max_df参数用来描述单词在文档中的最高出现率。假设max_df=0.5,代表一个单词在50%的文档中都出现过了,那么它只携带了非常少的信息,因此就不作为分词统计
一般很少设置min_df,因为min_df通常都会很小
生成朴素贝叶斯分类器
我们将特征训练集的特征空间train_features,以及训练集对应的分类train_labels传递给贝叶斯分类器clf,它会自动生成一个符合特征空间和对应分类的分类器
这里我们采用的是多项式贝叶斯分类器,其中alpha为平滑参数。为什么要使用平滑呢?因为如果一个单词在训练样本中没有出现,这个单词的概率就会被计算为0
但训练集样本只是整体的抽样情况,我们不能因为一个事件没有观察到,就认为整个事件的概率为0。为了解决这个问题,我们需要做平滑处理
当alpha = 1时,使用的是Laplace平滑。Laplace平滑就是采用加1的方式,来统计没有出现过的单词的概率。这样当训练样本很大的时候,加1得到的概率变化可以忽略不计,也同时避免了零概率的问题
当0 < alpha < 1时,使用的是Lidstone平滑。对于Lidstone平滑来说,alpha越小,迭代次数越多,精度越高。我们可以设置alpha为0.001
# 多项式贝叶斯分类器
from sklearn.naive_bayes import MultinomialNB
clf = MultinomialNB(alpha=0.001).fit(train_features, train_labels)
使用生成的分类器做预测
首先我们需要得到测试集的特征矩阵,方法是用训练集的分词创建一个TfidfVectorizer类
使用同样的stop_words和max_df,然后用这个TfidfVectorizer类对测试集的内容进行fit_transform拟合,得到测试集的特征矩阵test_features
test_tf = TfidfVectorizer(stop_words=stop_words, max_df=0.5, vocabulary=train_vocabulary)
test_features = test_tf.fit_transform(test_contents)
然后我们用训练好的分类器对新数据做预测。方法是使用predict函数,传入测试集的特征矩阵test_features,得到分类结果predicted_labels。predict函数做的工作就是求解所有后验概率并找出最大的那个
predicted_labels=clf.predict(test_features)
计算准确率
计算准确率实际上是对分类模型的评估。我们可以调用sklearn中的metrics包,在metrics中提供了accuracy_score函数,方便我们对实际结果和预测的结果做对比,给出模型的准确率
from sklearn import metrics
print metrics.accuracy_score(test_labels, predicted_labels)
总结
从数据挖掘的流程来看,一般包括了获取数据、数据清洗、模型训练、模型评估和模型部署这几个过程
sklearn中包含了大量的数据挖掘算法,比如三种朴素贝叶斯算法,我们只需要了解不同算法的适用条件,以及创建时所需的参数,就可以用模型帮我们进行训练
在模型评估中,sklearn提供了metrics包,帮我们对预测结果与实际结果进行评估
在文档分类的项目中,我们针对文档的特点,给出了基于分词的准备流程。一般来说NTLK包适用于英文文档,而jieba适用于中文文档
我们可以根据文档选择不同的包,对文档提取分词。这些分词就是贝叶斯分类中最重要的特征属性。基于这些分词,我们得到分词的权重,即特征矩阵
通过特征矩阵与分类结果,我们就可以创建出朴素贝叶斯分类器,然后用分类器进行预测,最后预测结果与实际结果做对比即可以得到分类器在测试集上的准确率
练习题
文档共有4种类型:女性、体育、文学、校园
训练集放到train文件夹里,测试集放到test文件夹里,停用词放到stop文件夹里
使用朴素贝叶斯分类对训练集进行训练,并对测试集进行验证,并给出测试集的准确率
# 中文文本分类
import os
import jieba
import warnings
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn import metrics
warnings.filterwarnings('ignore')
DIR = '/Users/txf/wwwroot/test/'
def cut_words(file_path):
"""
对文本进行切词
:param file_path: txt文本路径
:return: 用空格分词的字符串
"""
text_with_spaces = ''
text = open(file_path, 'r', encoding='gb18030').read()
textcut = jieba.cut(text)
for word in textcut:
text_with_spaces += word + ' '
return text_with_spaces
def loadfile(file_dir, label):
"""
将路径下的所有文件加载
:param file_dir: 保存txt文件目录
:param label: 文档标签
:return: 分词后的文档列表和标签
"""
file_list = os.listdir(file_dir)
words_list = []
labels_list = []
for file in file_list:
file_path = file_dir + '/' + file
words_list.append(cut_words(file_path))
labels_list.append(label)
return words_list, labels_list
stop_words = open(DIR + 'stop/stopword.txt', 'r', encoding='utf-8').read()
stop_words = stop_words.encode('utf-8').decode('utf-8-sig') # 列表头部\ufeff处理
stop_words = stop_words.split('\n') # 根据分隔符分隔
# 训练数据
train_words_list1, train_labels1 = loadfile(DIR + 'train/女性', '女性')
train_words_list2, train_labels2 = loadfile(DIR + 'train/体育', '体育')
train_words_list3, train_labels3 = loadfile(DIR + 'train/文学', '文学')
train_words_list4, train_labels4 = loadfile(DIR + 'train/校园', '校园')
train_words_list = train_words_list1 + train_words_list2 + train_words_list3 + train_words_list4
train_labels = train_labels1 + train_labels2 + train_labels3 + train_labels4
# 测试数据
test_words_list1, test_labels1 = loadfile(DIR + 'test/女性', '女性')
test_words_list2, test_labels2 = loadfile(DIR + 'test/体育', '体育')
test_words_list3, test_labels3 = loadfile(DIR + 'test/文学', '文学')
test_words_list4, test_labels4 = loadfile(DIR + 'test/校园', '校园')
test_words_list = test_words_list1 + test_words_list2 + test_words_list3 + test_words_list4
test_labels = test_labels1 + test_labels2 + test_labels3 + test_labels4
# 停词
stop_words = open(DIR + 'stop/stopword.txt', 'r', encoding='utf-8').read()
stop_words = stop_words.encode('utf-8').decode('utf-8-sig') # 列表头部\ufeff处理
stop_words = stop_words.split('\n') # 根据分隔符分隔
# 计算单词权重
tf = TfidfVectorizer(stop_words=stop_words, max_df=0.5)
train_features = tf.fit_transform(train_words_list)
# 上面fit过了,这里transform
test_features = tf.transform(test_words_list)
# 创建多项式朴素贝叶斯分类器并拟合训练数据
clf = MultinomialNB(alpha=0.001).fit(train_features, train_labels)
# 预测测试数据
predicted_labels = clf.predict(test_features)
# 比对预测数据与测试数据
print('准确率为:', metrics.accuracy_score(test_labels, predicted_labels))
todo
新闻 -> 词频 -> 情感分析