从零开始学Python【38】

您所在的位置:网站首页 朴素贝叶斯代码实现bank 从零开始学Python【38】

从零开始学Python【38】

2024-07-15 21:06| 来源: 网络整理| 查看: 265

【前言】

在《从零开始学Python【37】--朴素贝叶斯模型(理论部分)》中我们详细介绍了朴素贝叶斯算法的基本概念和理论知识,在这一期我们继续介绍该算法的实战案例。将会对高斯贝叶斯、多项式贝叶斯和伯努利贝叶斯三种分类器案例的做实战讲解。希望通过这部分内容的讲解,能够使读者对贝叶斯算法有一个较深的理解(文末有数据和源代码的下载链接)。

【高斯贝叶斯分类器】

面部皮肤区分数据集来自于UCI网站,该数据集含有两个部分,一部分为人类面部皮肤数据,该部分数据是由不同种族、年龄和性别人群的图片转换而成的;另一部分为非人类面部皮肤数据。两个部分的数据集一共包含245 057条样本和4个变量,其中用于识别样本是否为人类面部皮肤的因素是图片中的三原色R、G、B,它们的值均落在0~255;因变量为二分类变量,表示样本在对应的R、G、B值下是否为人类面部皮肤,其中1表示人类面部皮肤,2表示非人类面部皮肤。

通常情况下,研究人员会对样本是否为人类面部皮肤更加感兴趣,所以需要将原始数据集中因变量为1的值设置为正例、因变量为2的值设置为负例,代码如下:

代码语言:javascript复制# 导入第三方包 import pandas as pd # 读入数据 skin = pd.read_excel(r'C:\Users\Administrator\Desktop\Skin_Segment.xlsx') # 设置正例和负例 skin.y = skin.y.map({2:0,1:1}) skin.y.value_counts() out: 0 194198 1 50859

如上结果所示,因变量0表示负例,说明样本为非人类面部皮肤,一共包含194 198个观测;因变量1表示正例,说明样本为人类面部皮肤,一共包含50 859个观测;因变量值为0和1之间的比例为5:1。接下来将该数据集拆分为训练集和测试集,分别用于模型的构建和模型的评估,代码如下:

代码语言:javascript复制# 导入第三方模块 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) # 调用高斯朴素贝叶斯分类器的“类” 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

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

代码语言:javascript复制# 导入第三方包 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()

如上图所示,将混淆矩阵做了可视化处理,其中主对角线的数值表示正确预测的样本量,剩余的4 720条样本为错误预测的样本。经过对混淆矩阵的计算,可以得到模型的整体预测准确率为92.30%。

代码语言:javascript复制print('模型的准确率为:\n',metrics.accuracy_score(y_test, gnb_pred)) print('模型的评估报告:\n',metrics.classification_report(y_test, gnb_pred)) 模型的准确率为: 0.922957643026 模型的评估报告: precision recall f1-score support 0 0.93 0.97 0.95 48522 1 0.88 0.73 0.80 12743 avg / total 0.92 0.92 0.92 61265

进一步可以得到每个类别的预测精准率(precision=正确预测某类别的样本量/该类别的预测样本个数)和覆盖率(recall=正确预测某类别的样本量/该类别的实际样本个数),通过准确率、精准率和覆盖率的对比,模型的预测效果还是非常理想的。接下来绘制ROC曲线,用于进一步验证得到的结论,代码如下:

代码语言:javascript复制# 计算正例的预测概率,用于生成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()

如上图所示的ROC曲线,计算得到的AUC值为0.94,超过用于评判模型好坏的阈值0.8,故可以认为构建的贝叶斯分类器是非常理想的,进而验证了前文所得的结论。最后需要强调的是,利用高斯贝叶斯分类器对数据集进行分类时要求输入的数据集X为连续的数值型变量。

【多项式贝叶斯分类器】

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

代码语言:javascript复制# 读取数据 mushrooms = pd.read_csv(r'C:\Users\Administrator\Desktop\mushrooms.csv') # 数据的前5行,见表12-3 mushrooms.head()

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

代码语言:javascript复制# 将字符型数据做因子化处理,将其转换为整数型数据 columns = mushrooms.columns[1:] for column in columns: mushrooms[column] = pd.factorize(mushrooms[column])[0] mushrooms.head()

如上表所示,所有的字符型变量全部转换成了数值,而且每一列中的数值都代表了各自不同的字符值。需要注意的是,factorize函数返回的是两个元素的元组,第一个元素为转换成的数值,第二个元素为数值对应的字符水平,所以在类型转换时,需要通过索引方式返回因子化的值。接着就可以使用多项式贝叶斯分类器对如上数据集进行类别的预测,为了实现模型的验证,需要将该数据集拆分为训练集和测试集,代码如下:

代码语言:javascript复制# 将数据集拆分为训练集合测试集 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) # 构建多项式贝叶斯分类器的“类” 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('') plt.ylabel('') # 显示图形 plt.show()

在如上的混淆矩阵图中,横坐标代表测试数据集中的实际类别值,纵坐标为预测类别值,正确预测无毒的有981个样本,正确预测有毒的有786个样本。

代码语言:javascript复制# 模型的预测准确率 print('模型的准确率为:\n',metrics.accuracy_score(y_test, mnb_pred)) print('模型的评估报告:\n',metrics.classification_report(y_test, mnb_pred)) 模型的准确率为: 0.870014771049 模型的评估报告: precision recall f1-score support edible 0.85 0.92 0.88 1072 poisonous 0.90 0.82 0.86 959 avg / total 0.87 0.87 0.87 2031

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

代码语言:javascript复制# 计算正例的预测概率,用于生成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值下的概率不服从多项式分布的话,分类器的预测效果就不会很理想。通常情况下,会利用多项式贝叶斯分类器作文本分类,如一份邮件是否垃圾邮件、用户评论是否为正面等。

【伯努利贝叶斯分类器】

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

代码语言:javascript复制# 读入评论数据 evaluation = pd.read_excel(r'C:\Users\Administrator\Desktop\Contents.xlsx',sheetname=0) # 查看数据前10行,见表12-6 evaluation.head(10)

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

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

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

代码语言:javascript复制# 导入第三方包 import jieba # 加载自定义词库 jieba.load_userdict(r'C:\Users\Administrator\Desktop\all_words.txt') # 读入停止词 with open(r'C:\Users\Administrator\Desktop\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 上长 三根 空杆 装 2 没有 送货上门 失望 3 挺不错 破 口子 不知道 啥时候 弄 不错 老婆 怀孕 蚊香 不错 4 不错 效果

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

代码语言:javascript复制# 导入第三方包 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()

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

代码语言:javascript复制# 将数据集拆分为训练集和测试集 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()

如上结果所示,从混淆矩阵图形来看,伯努利贝叶斯分类器在预测数据集上的效果还是非常棒的,绝大多数的样本都被预测正确(因为主对角线上的数据非常大),而且总的预测准确率接近85%。

代码语言:javascript复制# 模型的预测准确率 print('模型的准确率为:\n',metrics.accuracy_score(y_test, bnb_pred)) print('模型的评估报告:\n',metrics.classification_report(y_test, bnb_pred)) 模型的准确率为: 0.84704998121 模型的评估报告: precision recall f1-score support Negative 0.82 0.90 0.86 1341 Positive 0.88 0.80 0.84 1320 avg / total 0.85 0.85 0.85 2661

从模型的评估报告来看,预测为消极情绪的覆盖率0.9相比于积极情绪的覆盖率0.8要更高一些,但总体来说模型的预测效果还是不错的。同理,再绘制一下关于模型在测试数据集上的ROC曲线,代码如下:

代码语言:javascript复制# 计算正例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()

如上图所示,绘制的ROC曲线所对应的AUC值为0.93,同样是一个非常高的数值,再结合模型准确率、覆盖率等指标,可以认为该模型在测试数据集上的预测效果是非常理想的。需要说明的是,如果训练数据集是关于词语在各文档中出现的频次,直接调用BernoulliNB类是没有问题的,因为该“类”中参数binarize默认值为0,即如果词的频次大于0,则对应的变量值在模型运算时会转换成1,否则转换为0。

【结语】

OK,关于贝叶斯算法的实战我们就分享到这里,如果你有任何问题,欢迎在公众号的留言区域表达你的疑问。同时,也欢迎各位朋友继续转发与分享文中的内容,让更多的人学习和进步。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3