本篇文章是对最简单的朴素贝叶斯网络的运用进行python实践,先对iris鸢尾花数据集做一个分类预实验,再对实际新闻进行分类预测
有关贝叶斯网络原理可以查看这篇文章 :贝叶斯网络基础
一、iris鸢尾花数据集分类
1、开头先导入相关模块:
import matplotlib.pyplot as plt # 绘图
from sklearn.datasets import load_iris #导入鸢尾花集
from sklearn.model_selection import train_test_split #对数据集进行切分
from sklearn.naive_bayes import MultinomialNB # 朴素贝叶斯网络模型
2、导入鸢尾花数据集:
X = load_iris().data # 数据集
Y = load_iris().target # 相应类别标签
鸢尾花数据集一共有150行,每一行代表一个鸢尾花的一些属性,比如花瓣长度、花瓣宽度等;数据集中一共有3类,所有标签类别为0 1 2
数据集data(没有展现完)
类别标签:
3、鸢尾花数据集分类
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.2, random_state=0)
#将数据集按照 训练集比测试集为8:2的比例随机拆分数据集
clf = MultinomialNB() # 建立朴素贝叶斯网络
clf.fit(X_train, y_train) # 带入训练集训练模型
pre = clf.predict(X_test) # 预测测试集中特征矩阵所属的类别
print('预测集标签')
print(y_test)
print('预测结果')
print(pre)
打印出来看看,预测标签和预测结果有很多不吻合的
4、计算预测结果
N = len(pre)
right = 0
for i in range(N):
if pre[i] == y_test[i]:
right += 1
Accuracy=right/N
print(Accuracy)
发现结果只有0.5666666,预测结果十分不理想
5、分析原因
鸢尾花数据集一共只有150个,训练集相对来说是远远不够的,数据太少导致拟合效果不足(欠拟合)。下面增加按倍数增加鸢尾花数据集,使得数据集按相同特征产生足够大的数据集,我这里从1倍逐步扩大到10倍(也就是从150个数据集逐步增加到1500个数据集),然后画出它的准确率曲线。对源代码增加一个For 循环即可:
Accuracy=[]
for j in range(10):
X = load_iris().data*(j+1)
Y = load_iris().target*(j+1)
#print(X)
#print(Y)
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.2, random_state=0)
clf = MultinomialNB() # 拟合模型
clf.fit(X_train, y_train) # 训练模型
pre = clf.predict(X_test) # 预测测试集中特征矩阵所属的类别
print('预测集标签')
print(y_test)
print('预测结果')
print(pre)
N = len(pre)
right = 0
for i in range(N):
if pre[i] == y_test[i]:
right += 1
Accuracy.append(right/N) # 计算准确率
plt.plot(list(range(10)),Accuracy)
plt.show()
准确率变化图像如下,发现随着数据集增加,模型预测准确率不断增加,当数据集增加到6倍左右,准确率变为百分之百。这就提醒初学者,对于机器学习中的模型,只有在大量样本的训练条件下才能作出很好的预测。
二、新闻分类
1、新闻文本预处理,即把新闻变成数据向量(矩阵)
主要思路:对每一条新闻进行分词,每一条新闻变成词语的列表,统计所有新闻中出现的词语,每一个词语代表矩阵一列,有多少个词语矩阵就有多少列(设一共有 M个词语)。对每一条新闻初始化为全为0的M维向量,这条新闻中出现的词语,在相应的列标为1,其余为0不变。
例如,下面三句话作为一个总文本:
我喜欢你
我正在削苹果
我喜欢吃苹果
其中一共出现7个词: ‘我’、‘喜欢’、‘你’、‘正在’、‘削’、‘苹果’、‘吃’
那么向量总长度为7,按照上一行的顺序将每一个词定位在一个列,生成如下向量(词的排列顺序并不干扰)
[1 1 1 0 0 0 0]
[1 0 0 1 1 1 0]
[1 1 0 0 0 1 1]
这样每一个向量表示矩阵一行,就得到相应总文本的矩阵(当然,一个词出现n次,对应位子也可以是n,也就是说向量中的非0元素是词语出现的频数)
具体的文本向量化可以参照我之前的一篇文章:
文本向量化方法:TF-IDF文本向量化模型
这里值得注意的是:
TF模型就是词频的文本向量化方法,它是TF-IDF文本向量化模型的一部分;朴素贝叶斯网络用TF模型得到的向量进行训练测试,其效果会比利用TF-IDF的号,因为TF模型的向量是离散的,只取0 1 2 3 等较小整数,而TF-IDF的向量是连续的从0-1之间的小数。朴素贝叶斯网络对离散数据的训练测试能力要强于连续数据的,所以这里仅利用TF模型向量化。具体地可以查看上面的链接。
2、引用sklearn库中一些工具获取文本向量:
(在这里,我的文本已经是经过分词处理的,用txt文件保存好的,每一行代表一个新闻)
老样子,先导入用到的模块
import numpy as np
np.set_printoptions(threshold=np.inf)
from sklearn.feature_extraction.text import CountVectorizer
# 计算TF的模块
from sklearn.naive_bayes import MultinomialNB
# 朴素贝叶斯模型
#from sklearn.feature_extraction.text import TfidfTransformer
# 计算TF-IDF矩阵的模块,我这里导入TF-IDF是为了待会与TF的结果比较
导入新闻文本以及对应标签
train_txt=open('train_contents.txt','r',encoding='utf-8').read().split('\n')
# 训练集新闻文本
test_txt=open('test_contents.txt','r',encoding='utf-8').read().split('\n')
# 测试集新闻文本
all_txt=train_txt+test_txt # 总文本
train_labels=open('train_labels.txt','r',encoding='utf-8').read().split('\n')
# 训练集对应标签
test_labels=open('test_labels.txt','r',encoding='utf-8').read().split('\n')
# 测试集对应标签
文本向量化:
count_vo=CountVectorizer() # 初始化这个对象
count_alls=count_vo.fit_transform(all_txt) # 构造一个全部文本的TF对象
count_v1=CountVectorizer(vocabulary=count_vo.vocabulary_)
count_train=count_v1.fit_transform(train_txt) # 求得训练集的TF矩阵
count_v2=CountVectorizer(vocabulary=count_vo.vocabulary_)
test_train=count_v2.fit_transform(test_txt) # 求得测试集TF矩阵
3、朴素贝叶斯模型训练与预测
clf = MultinomialNB() #拟合模型
clf.fit(count_train,train_labels) #训练模型
pre = clf.predict(test_train) #预测测试集中特征矩阵所属的类别
# 以下是求预测准确率
nums=0
for i in range(len(pre)):
if pre[i]==test_labels[i]:
nums+=1
accuracy=nums/len(pre)
print(accyracy)
预测准确率:
4、改用TF-IDF向量进行训练和测试,增加以下代码即可
tf_idf=TfidfTransformer()
train_data=tf_idf.fit(count_train).transform(count_train)
test_data=tf_idf.fit(test_train).transform(test_train)
这样train_data、test_data就是TF-IDF方式的向量了,带入贝叶斯模型中得出预测准确率:
能看出,准确率相对于前者是下降一点的
5、比较上一次利用支持向量机SVM的实验结果(同样的文本),发现这两种方法的结果都很接近,都在0.85附近,但SVM的结果低了一点点。
SVM中用主张用的向量化方法是TF-IDF,因为支持向量机可以对连续数据进行很好的分割,具体可查看:
基于支持向量机SVM的新闻分类实践
需要文本资料的朋友可以私聊我邮箱,一起学习共同进步,加油