朴素贝叶斯模型

高斯贝叶斯分类器

高斯贝叶斯分类器的计算过程还是比较简单的,其关键的核心是假设数值型变量服从正态分布,如果实际数据近似服从正态分布,分类结果会更加准确。sklearn模块提供了实现该分类器的计算功能,它就是naive_bayes子模块中的GaussianNB类,由于该“类”仅包含一个参数,且参数的默认值是以各类别的频率作为先验概率,因此在调用GaussianNB类构造高斯贝叶斯分类器时,可以不传递任何参数值

GaussianNB(priors=None)

priors:用于指定因变量各类别的先验概率,默认以数据集中的类别频率作为先验概率。

高斯贝叶斯分类器实战

面部皮肤区分数据集来自于UCI网站,该数据集含有两个部分,一部分为人类面部皮肤数据,该部分数据是由不同种族、年龄和性别人群的图片转换而成的;另一部分为非人类面部皮肤数据。两个部分的数据集一共包含245 057条样本和4个变量,其中用于识别样本是否为人类面部皮肤的因素是图片中的三原色R、G、B,它们的值均落在0~255;因变量为二分类变量,表示样本在对应的R、G、B值下是否为人类面部皮肤,其中1表示人类面部皮肤,2表示非人类面部皮肤。通常情况下,研究人员会对样本是否为人类面部皮肤更加感兴趣,所以需要将原始数据集中因变量为1的值设置为正例、因变量为2的值设置为负例

# 导入第三方包
import pandas as pd
# 读入数据
skin = pd.read_excel(r'Skin_Segment.xlsx')
# 设置正例和负例
skin.y = skin.y.map({2:0,1:1})
skin.y.value_counts()

out:
0    194198
1     50859
Name: y, dtype: int64
skin.head()

	B	G	R	y
0	74	85	123	1
1	73	84	122	1
2	72	83	121	1
3	70	81	119	1
4	70	81	119	1

如上结果所示,因变量0表示负例,说明样本为非人类面部皮肤,一共包含194 198个观测;因变量1表示正例,说明样本为人类面部皮肤,一共包含50 859个观测;因变量值为0和1之间的比例为5:1。

# 导入第三方模块
from sklearn import model_selection
# 样本拆分
X_train,X_test,y_train,y_test = model_selection.train_test_split(skin.iloc[:,:3], skin.y, 
                                                                 test_size = 0.25, random_state=1234)
# 导入第三方模块
from sklearn import naive_bayes
# 调用高斯朴素贝叶斯分类器的“类”
gnb = naive_bayes.GaussianNB()
# 模型拟合
gnb.fit(X_train, y_train)
# 模型在测试数据集上的预测
gnb_pred = gnb.predict(X_test)
# 各类别的预测数量
pd.Series(gnb_pred).value_counts()

out:
0    50630
1    10635
dtype: int64

通过构建高斯朴素贝叶斯分类器,实现测试数据集上的预测,经统计,预
测为负例的一共有50 630条样本、预测为正例的一共有10 635条样本。为检验模型在测试数据集上的预测效果,需要构建混淆矩阵和绘制ROC曲线,其中混淆矩阵用于模型准确率、覆盖率、精准率指标的计算;ROC曲线用于计算AUC值,并将AUC值与0.8相比,判断模型的拟合效果

# 导入第三方包
from sklearn import metrics
import matplotlib.pyplot as plt
import seaborn as sns
# 构建混淆矩阵
cm = pd.crosstab(gnb_pred,y_test)
# 绘制混淆矩阵图
sns.heatmap(cm, annot = True, cmap = 'GnBu', fmt = 'd')
# 去除x轴和y轴标签
plt.xlabel('Real')
plt.ylabel('Predict')
# 显示图形
plt.show()

print('模型的准确率为:\n',metrics.accuracy_score(y_test, gnb_pred))
print('模型的评估报告:\n',metrics.classification_report(y_test, gnb_pred))

out:
模型的准确率为:
 0.9229576430261976
模型的评估报告:
               precision    recall  f1-score   support

           0       0.93      0.97      0.95     48522
           1       0.88      0.73      0.80     12743

    accuracy                           0.92     61265
   macro avg       0.90      0.85      0.88     61265
weighted avg       0.92      0.92      0.92     61265

在这里插入图片描述
将混淆矩阵做了可视化处理,其中主对角线的数值表示正确预测的样本量,剩余的4 720条样本为错误预测的样本。经过对混淆矩阵的计算,可以得到模型的整体预测准确率为92.30%;进一步可以得到每个类别的预测精准率(precision=正确预测某类别的样本量/该类别的预测样本个数)和覆盖率(recall=正确预测某类别的样本量/该类别的实际样本个数),通过准确率、精准率和覆盖率的对比,模型的预测效果还是非常理想的。接下来绘制
ROC曲线,用于进一步验证得到的结论

# 计算正例的预测概率,用于生成ROC曲线的数据
y_score = gnb.predict_proba(X_test)[:,1]
fpr,tpr,threshold = metrics.roc_curve(y_test, y_score)
# 计算AUC的值
roc_auc = metrics.auc(fpr,tpr)

# 绘制面积图
plt.stackplot(fpr, tpr, color='steelblue', alpha = 0.5, edgecolor = 'black')
# 添加边际线
plt.plot(fpr, tpr, color='black', lw = 1)
# 添加对角线
plt.plot([0,1],[0,1], color = 'red', linestyle = '--')
# 添加文本信息
plt.text(0.5,0.3,'ROC curve (area = %0.2f)' % roc_auc)
# 添加x轴与y轴标签
plt.xlabel('1-Specificity')
plt.ylabel('Sensitivity')
# 显示图形
plt.show()

在这里插入图片描述
计算得到的AUC值为0.94,超过用于评判模型好坏的阈值0.8,故可以认为构建的贝叶斯分类器是非常理想的,进而验证了前文所得的结论。

最后需要强调的是,利用高斯贝叶斯分类器对数据集进行分类时要求输入的数据集X为连续的数值型变量。

多项式贝叶斯分类器

如果数据集中的自变量X均为离散型变量,就无法使用高斯贝叶斯分类器,而应该选择多项式贝叶斯分类器。

多项式贝叶斯分类器的计算过程也同样比较简单,如需使用Python实现该分类器的构造,可以直接导入sklearn的子模块naive_bayes模块,然后调用MultinomialNB类。

MultinomialNB(alpha = 1.0, fit_prior = True, class_prior = None)

alpha:用于指定平滑系数α的值,默认为1.0。

fit_prior:bool类型参数,是否以数据集中各类别的比例作为P(Ci)的先验概率,默认为True。

class_prior:用于人工指定各类别的先验概率P(Ci),如果指定该参数,则参数fit_prior不再有效。

多项式贝叶斯分类器实战

蘑菇数据集来自于UCI网站,一共包含8 124条观测和22个变量,其中因变量为type,表示蘑菇是否有毒,剩余的自变量是关于蘑菇的形状、表面光滑度、颜色、生长环境等。首先将该数据集读入Python

# 导入第三方包
import pandas as pd
# 读取数据
mushrooms = pd.read_csv(r'mushrooms.csv')
# 数据的前5行
mushrooms.head()

out:

type	cap_shape	cap_surface	cap_color	bruises	odor	gill_attachment	gill_spacing	gill_size	gill_color	...	stalk_surface_above_ring	stalk_surface_below_ring	stalk_color_above_ring	stalk_color_below_ring	veil_color	ring_number	ring_type	spore_print_color	population	habitat
0		poisonous	convex	smooth	brown	yes	pungent	free	close	narrow	black	...	smooth	smooth	white	white	white	one	pendant	black	scattered	urban
1		edible	convex	smooth	yellow	yes	almond	free	close	broad	black	...	smooth	smooth	white	white	white	one	pendant	brown	numerous	grasses
2		edible	bell	smooth	white	yes	anise	free	close	broad	brown	...	smooth	smooth	white	white	white	one	pendant	brown	numerous	meadows
3		poisonous	convex	scaly	white	yes	pungent	free	close	narrow	brown	...	smooth	smooth	white	white	white	one	pendant	black	scattered	urban
4		edible	convex	smooth	gray	no	none	free	crowded	broad	black	...	smooth	

表中的所有变量均为字符型的离散值,由于Python建模过程中必须要求自
变量为数值类型,因此需要对这些变量做因子化处理,即把字符值转换为对应的数值。接下来利用pandas模块中的factorize函数对离散的自变量进行数值转换

# 将字符型数据作因子化处理,将其转换为整数型数据
columns = mushrooms.columns[1:]
for column in columns:
    mushrooms[column] = pd.factorize(mushrooms[column])[0]
mushrooms.head()

out:
	type	cap_shape	cap_surface	cap_color	bruises	odor	gill_attachment	gill_spacing	gill_size	gill_color	...	stalk_surface_above_ring	stalk_surface_below_ring	stalk_color_above_ring	stalk_color_below_ring	veil_color	ring_number	ring_type	spore_print_color	population	habitat
0	poisonous	0	0	0	0	0	0	0	0	0	...	0	0	0	0	0	0	0	0	0	0
1	edible		0	0	1	0	1	0	0	1	0	...	0	0	0	0	0	0	0	1	1	1
2	edible		1	0	2	0	2	0	0	1	1	...	0	0	0	0	0	0	0	1	1	2
3	poisonous	0	1	2	0	0	0	0	0	1	...	0	0	0	0	0	0	0	0	0	0
4	edible		0	0	3	1	3	0	1	1	0	...	0	

所有的字符型变量全部转换成了数值,而且每一列中的数值都代表了各自
不同的字符值。需要注意的是,factorize函数返回的是两个元素的元组,第一个元素为转换成的数值,第二个元素为数值对应的字符水平,所以在类型转换时,需要通过索引方式返回因子化的值

from sklearn import model_selection
# 将数据集拆分为训练集合测试集
Predictors = mushrooms.columns[1:]
X_train,X_test,y_train,y_test = model_selection.train_test_split(mushrooms[Predictors], mushrooms['type'], 
                                                                 test_size = 0.25, random_state = 10)
from sklearn import naive_bayes
from sklearn import metrics
import seaborn as sns
import matplotlib.pyplot as plt
# 构建多项式贝叶斯分类器的“类”
mnb = naive_bayes.MultinomialNB()
# 基于训练数据集的拟合
mnb.fit(X_train, y_train)
# 基于测试数据集的预测
mnb_pred = mnb.predict(X_test)
# 构建混淆矩阵
cm = pd.crosstab(mnb_pred,y_test)
# 绘制混淆矩阵图
sns.heatmap(cm, annot = True, cmap = 'GnBu', fmt = 'd')
# 去除x轴和y轴标签
plt.xlabel('Real')
plt.ylabel('Predict')
# 显示图形
plt.show()

# 模型的预测准确率
print('模型的准确率为:\n',metrics.accuracy_score(y_test, mnb_pred))
print('模型的评估报告:\n',metrics.classification_report(y_test, mnb_pred))

out:
模型的准确率为:
 0.8700147710487445
模型的评估报告:
               precision    recall  f1-score   support

      edible       0.85      0.92      0.88      1072
   poisonous       0.90      0.82      0.86       959

    accuracy                           0.87      2031
   macro avg       0.87      0.87      0.87      2031
weighted avg       0.87      0.87      0.87      2031

在这里插入图片描述
在如上的混淆矩阵图中,横坐标代表测试数据集中的实际类别值,纵坐标为预测类别值,正确预测无毒的有981个样本,正确预测有毒的有786个样本。基于混淆矩阵的进一步运算,可以得到如上所示的两部分结果,并从中发现,模型在测试数据集上的整体预测准确率为87%,
而且从各类别值来看,无毒蘑菇的预测覆盖率为92%、有毒蘑菇的预测覆盖率为82%。总体来说,模型的预测效果还是非常理想的,接下来继续绘制ROC曲线,查看对应的AUC值的大小,

from sklearn import metrics
# 计算正例的预测概率,用于生成ROC曲线的数据
y_score = mnb.predict_proba(X_test)[:,1]
fpr,tpr,threshold = metrics.roc_curve(y_test.map({'edible':0,'poisonous':1}), y_score)
# 计算AUC的值
roc_auc = metrics.auc(fpr,tpr)

# 绘制面积图
plt.stackplot(fpr, tpr, color='steelblue', alpha = 0.5, edgecolor = 'black')
# 添加边际线
plt.plot(fpr, tpr, color='black', lw = 1)
# 添加对角线
plt.plot([0,1],[0,1], color = 'red', linestyle = '--')
# 添加文本信息
plt.text(0.5,0.3,'ROC curve (area = %0.2f)' % roc_auc)
# 添加x轴与y轴标签
plt.xlabel('1-Specificity')
plt.ylabel('Sensitivity')
# 显示图形
plt.show()

在这里插入图片描述
ROC曲线下的面积为0.94,超过阈值0.8,可以认为模型的效果是可以接受
的。需要注意的是,当因变量为字符型的值时,子模块metrics中的函数roc_curve必须传入数值型的因变量(如代码所示,将字符值和数值做了映射),否则会报错误信息。对于离散型自变量的数据集而言,在分类问题上并非都可以使用多项式贝叶斯分类器,如果自变量在特定y值下的概率不服从多项式分布的话,分类器的预测效果就不会很理想。通常情况下,会利用多项式贝叶斯分类器作文本分类,如一份邮件是否垃圾邮件、用户评论是否
为正面等。

伯努利贝叶斯分类器

当数据集中的自变量X均为0-1二元值时(例如在文本挖掘中,判断某个词语是否出现在句子中,出现用1表示,不出现用0表示),通常会优先选择伯努利贝叶斯分类器。利用该分类器计算概率值P(X|Ci)时,会假设自变量X的条件概率满足伯努利分布

伯努利贝叶斯分类器的计算与多项式贝叶斯分类器的计算非常相似,在文本分类问题中,如果构造的数据集是关于词语出现的次数,通常会选择多项式贝叶斯分类器进行预测;如果构造的数据集是关于词语是否会出现的0-1值,则会选择伯努利贝叶斯分类器进行预测。当读者需要构造伯努利贝叶斯分类器时,可以直接调用sklearn子模块naive_bayes中的BernoulliNB类。

BernoulliNB (alpha = 1.0, binarize=0.0, fit_prior = True, class_prior = None)

alpha:用于指定平滑系数α的值,默认为1.0。
binarize:如果该参数为浮点型数值,则将以该值为界限,当自变量的值大于该值时,自变量的值将被转换为1,否则被转换为0;如果该参数为None时,则默认训练数据集的自变量均为0-1值。

fit_prior:bool类型参数,是否以数据集中各类别的比例作为P(Ci
)的先验概率,默认为True。

class_prior:用于人工指定各类别的先验概率P(Ci),如果指定该参数,则参数fit_prior不再有效。

用户对其购买的蚊帐进行评论,该数据集是通过爬虫的方式获得,一共包含10 644条评论,数据集中的Type变量为评论所对应的情绪。首先将爬虫获得的数据集读入Python中,并预览前几行数据

import pandas as pd
# 读入评论数据
evaluation = pd.read_excel(r'Contents.xlsx',sheet_name=0)
# 查看数据前10行
evaluation.head(10)


out:
NickName	Date	Content	Type
0	AdJQKzNaZWAV	2016-04-14 23:30:42	想知道是不是卖家给我发错货了,怎么四个连接铁通的仅一个能连上,**块钱的东西说便宜也不至于廉...	Negative
1	sdmjk	2013-06-24 22:37:51	垃圾。\n两个管两头一样粗,得自己用钳子摄细才能装上\n管子很软很细\n总的评价 - 就是两...	Negative
2	f***n	2015-06-05 21:10:31	我就无语了...难弄到死..又没说明书..过段差评..	Negative
3	jd_817039867	2014-04-13 22:43:38	不满意,明明写的落地!结果差一截!而且自垂度不怎么好~还要用夹子夹!没有我在附近小超市买的质...	Negative
4	jd_wscj529	2014-06-09 13:06:17	标的次日到达,结果快递用了四天,蚊帐杆底座太小,管壁太薄,而且蚊帐也没宣传那么垂地,此次购物...	Negative
5	q***r	2017-04-25 00:24:25	真的很好,比超市卖的便宜多了,刚回来打算在买个给我嫂子家,发货也很快没想到这么便宜也能买的这...	Positive
6	A***2017-05-11 06:53:47	最不满意的一次网购。直接看图。1.8的床两头1.8中间只有1.5了,两边的纱像少了一截,绷得...	Negative
7***2017-05-15 11:05:01	很不错的,就是拉丝不够好啊	Positive
8	j***w	2016-05-15 09:25:49	薄,漂亮	Positive
9	1***n	2017-05-15 09:00:43	味道有点大,线头有点多。装好后有点摇晃,拉链处开了几处,要不是等着急用,真心是要退	Positive

数据集包含4个字段,分别是用户昵称、评价时间、评价内容和对应的评价
情绪。从评价内容来看,会有一些“脏”文本在内,如数字、英文等,所以需要将这些“脏”文本删除

# 运用正则表达式,将评论中的数字和英文去除
evaluation.Content = evaluation.Content.str.replace('[0-9a-zA-Z]','')
evaluation.head()

out:
NickName	Date	Content	Type
0	AdJQKzNaZWAV	2016-04-14 23:30:42	想知道是不是卖家给我发错货了,怎么四个连接铁通的仅一个能连上,**块钱的东西说便宜也不至于廉...	Negative
1	sdmjk	2013-06-24 22:37:51	垃圾。\n两个管两头一样粗,得自己用钳子摄细才能装上\n管子很软很细\n总的评价 - 就是两...	Negative
2	f***n	2015-06-05 21:10:31	我就无语了...难弄到死..又没说明书..过段差评..	Negative
3	jd_817039867	2014-04-13 22:43:38	不满意,明明写的落地!结果差一截!而且自垂度不怎么好~还要用夹子夹!没有我在附近小超市买的质...	Negative
4	jd_wscj529	2014-06-09 13:06:17	标的次日到达,结果快递用了四天,蚊帐杆底座太小,管壁太薄,而且蚊帐也没宣传那么垂地,此次购物...	Negative

经过数据的初步清洗后,下一步要做的就是对文本进行切词,但在切词前,通常需要引入用户自定义的词库和停止词。利用词典的目的是将无法正常切割的词实现正确切割(如“沙瑞金书记”会被切词为“沙”“瑞金”“书记”,为了避免这种情况,就需要将类似“沙瑞金”这样的词组合为词库),使用停止词的目的是将句子中无意义的词语删除(如“的”“啊”“我们”等)。

# 导入第三方包
import jieba

# 加载自定义词库
jieba.load_userdict(r'all_words.txt')

# 读入停止词
with open(r'mystopwords.txt', encoding='UTF-8') as words:
    stop_words = [i.strip() for i in words.readlines()]

# 构造切词的自定义函数,并在切词过程中删除停止词
def cut_word(sentence):
    words = [i for i in jieba.lcut(sentence) if i not in stop_words]
    # 切完的词用空格隔开
    result = ' '.join(words)
    return(result)
# 对评论内容进行批量切词
words = evaluation.Content.apply(cut_word)
# 前5行内容的切词效果
words[:5]

out:
0                  想 卖家 给我发 错货 四个 连接 铁通 块钱 便宜 廉价 退货
1           垃圾 \n 钳子 摄细 装 \n 管子 很软 \n 评价         垃圾
2                       我就 无语 难弄 .. 说明书 .. 过段 差评 ..
3    不满意 写 落地 差一截 垂度 ~ 夹子 夹 没有 超市 买 质量好 换季 卖得 价钱 便宜
4      标的 到达 快递 四天 蚊帐 底座 太小 管壁 太薄 蚊帐 也没 宣传 垂地 购物 失败
Name: Content, dtype: object

如上结果所示,通过调入第三方包jieba实现中文的切词,并在切词过程中加入自定义词库和删除停止词。接下来利用如上的切词结果,构造文档词条矩阵,矩阵的每一行代表一个评论内容,矩阵的每一列代表切词后的词语,矩阵的元素为词语在文档中出现的频次

# 导入第三方包
from sklearn.feature_extraction.text import CountVectorizer
# 计算每个词在各评论内容中的次数,并将稀疏度为99%以上的词删除
counts = CountVectorizer(min_df = 0.01)
# 文档词条矩阵
dtm_counts = counts.fit_transform(words).toarray()
# 矩阵的列名称
columns = counts.get_feature_names()
# 将矩阵转换为数据框--即X变量
X = pd.DataFrame(dtm_counts, columns=columns)
# 情感标签变量
y = evaluation.Type
X.head()

out:
	一根	下单	不值	不好	不想	不满意	不知道	不行	不错	买回来	...	还好	还行	退货	送货	速度	钢管	防蚊	非常好	颜色	麻烦
0	0	0	0	0	0	0	0	0	0	0	...	0	0	1	0	0	0	0	0	0	0
1	0	0	0	0	0	0	0	0	0	0	...	0	0	0	0	0	0	0	0	0	0
2	0	0	0	0	0	0	0	0	0	0	...	0	0	0	0	0	0	0	0	0	0
3	0	0	0	0	0	1	0	0	0	0	...	0	0	0	0	0	0	0	0	0	0
4	0	0	0	0	0	0	0	0	0	0	...	0	0	0	0	0	0	0	0	0	0
5 rows × 99 columns

将文档词条矩阵转换为数据框后得到一个庞大的稀疏矩阵,即数据框中的
大部分值为0。为了避免数据框的列数过多,在构造文档词条矩阵时做了相应的限制条件,即代码中的CountVectorizer(min_df = 0.01),表示词语所对应的文档数目必须在所有文档中至少占1%的比例,最终得到表12-8中所呈现的99个变量。有了如上的数据框,接下来要做的就是将数据集拆分为训练集和测试集,并利用训练集构建伯努利贝叶斯分类器,利用测试集对分类器的预测效果进行评估

from sklearn import model_selection
from sklearn import naive_bayes
from sklearn import metrics
import matplotlib.pyplot as plt
import seaborn as sns
# 将数据集拆分为训练集和测试集
X_train,X_test,y_train,y_test = model_selection.train_test_split(X,y,test_size = 0.25, random_state=1)
# 构建伯努利贝叶斯分类器
bnb = naive_bayes.BernoulliNB()
# 模型在训练数据集上的拟合
bnb.fit(X_train,y_train)
# 模型在测试数据集上的预测
bnb_pred = bnb.predict(X_test)
# 构建混淆矩阵
cm = pd.crosstab(bnb_pred,y_test)
# 绘制混淆矩阵图
sns.heatmap(cm, annot = True, cmap = 'GnBu', fmt = 'd')
# 去除x轴和y轴标签
plt.xlabel('Real')
plt.ylabel('Predict')
# 显示图形
plt.show()

# 模型的预测准确率
print('模型的准确率为:\n',metrics.accuracy_score(y_test, bnb_pred))
print('模型的评估报告:\n',metrics.classification_report(y_test, bnb_pred))

out:
模型的准确率为:
 0.8467317806160781
模型的评估报告:
               precision    recall  f1-score   support

    Negative       0.82      0.89      0.85      1341
    Positive       0.88      0.80      0.84      1321

    accuracy                           0.85      2662
   macro avg       0.85      0.85      0.85      2662
weighted avg       0.85      0.85      0.85      2662

在这里插入图片描述

# 计算正例Positive所对应的概率,用于生成ROC曲线的数据
y_score = bnb.predict_proba(X_test)[:,1]
fpr,tpr,threshold = metrics.roc_curve(y_test.map({'Negative':0,'Positive':1}), y_score)
# 计算AUC的值
roc_auc = metrics.auc(fpr,tpr)

# 绘制面积图
plt.stackplot(fpr, tpr, color='steelblue', alpha = 0.5, edgecolor = 'black')
# 添加边际线
plt.plot(fpr, tpr, color='black', lw = 1)
# 添加对角线
plt.plot([0,1],[0,1], color = 'red', linestyle = '--')
# 添加文本信息
plt.text(0.5,0.3,'ROC curve (area = %0.2f)' % roc_auc)
# 添加x轴与y轴标签
plt.xlabel('1-Specificity')
plt.ylabel('Sensitivity')
# 显示图形
plt.show()

在这里插入图片描述

  • 0
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值