朴素贝叶斯
1)基础思想:对于给出的待分类项,求解在此项出现的条件下各个类别出现的概率,哪个最大,就认为此分类项属于哪个类别。
2)优点:
可以和决策树、神经网络分类算法相媲美,能运用于大型数据库中。
方法简单,分类准确率高,速度快,所需估计的参数少,对于缺失数据不敏感。
3)缺点:
假设一个属性对定类的影响独立于其他的属性值,这往往并不成立。(喜欢吃番茄、鸡蛋,却不喜欢吃番茄炒蛋)。
需要知道先验概率。
根据自变量X的不同类型,有三种分类器。
若X为连续的数值型,选择高斯贝叶斯分类器;
若X为离散的数据类型,选择多项式贝叶斯分类器;
若X为0-1二元值,选择伯努利贝叶斯分类器。
以上核心假设为自变量之间条件独立。
优点:
算法在运算过程中简单高效,对大数量训练和查询时具有较高的速度。即使使用超大规模的训练集,针对每个项目通常也只会有相对较少的特征数,并且对项目的训练和分类也仅仅是特征概率的数学运算而已;
拥有古典概率的理论支撑,分类效率稳定;
对缺失数据和异常数据不太敏感。
支持增量式运算,即可以实时的对新增的样本进行训练;
朴素贝叶斯对结果解释容易理解;
对数据较少的情况下仍然有效;
可以处理多类别问题。
缺点:
模型的判断结果依赖于先验概率,会导致分类结果存在一定的错误率;
对输入的X要去相同特征(变量均为数值型或离散型或0-1型);
模型的前提假设在实际应用中很难满足;
由于使用了样本属性独立性的假设,所以如果样本属性有关联时其效果不好。
改进措施:
下溢出问题:对概率取对数;
词袋模型在解决文档分类问题上比词集模型好;
移除停用词(对分类基本上没有帮助的词,如助词、语气词等)。
注:Bag-of-Words词袋模型,经常用在自然语言处理和信息检索当中.在词袋模型中,一篇文本(文章)被表示成"装着词的袋子",也就是说忽略文章的词序和语法,句法;将文章看做词的组合,文中出现的每个词都是独立的,不依赖于其他词.Set-of-Words词集模型SoW:用0-1作为文章中词的数量表示.两者之间的区别在于词的数量表示不同,一个用0-1,一个用词频。
应用领域:
欺诈检测;一封电子邮件是否是垃圾邮件;一篇文章应该分到科技、政治,还是体育类;一段文字表达的是积极的情绪还是消极的情绪;人脸识别等。
一、高斯贝叶斯分类器
利用三原色RGB区分是否为人类面部皮肤,当均落在0~255时,为人类皮肤
# 导入第三方包
import pandas as pd
# 读入数据
skin = pd.read_excel(r'F:\Skin_Segment.xlsx')
skin.head()
1表示人类皮肤,2表示非人类皮肤
将2设置为负例,因变量0;1设置为正例,因变量1
通过map函数
# 设置正例和负例
skin.y = skin.y.map({2:0,1:1})
skin.y.head()
统计各自个数
skin.y.value_counts()
拆分数据集
#提取自变量,通过iloc获取数据框子集
skin.iloc[:,:3].head()
# 导入第三方模块
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()
得到预测为负例一共有50630个,预测为正例有10635个
为检验预测效果,构建混淆矩阵和绘制ROC曲线
# 导入第三方包
from sklearn import metrics
import matplotlib.pyplot as plt
import seaborn as sns
# 构建混淆矩阵
cm = pd.crosstab(gnb_pred,y_test)
cm
# 绘制混淆矩阵图
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))
整体预测率为92.30%
并且可得预测率和覆盖率较高
# 计算正例的预测概率,而非实际的预测值,用于生成ROC曲线的数据
y_score = gnb.predict_proba(X_test)[:,1]
y_score
#fpr表示1-Specificity,tpr表示Sensitivity
fpr,tpr,threshold = metrics.roc_curve(y_test, y_score)
fpr,tpr,threshold
# 计算AUC的值
roc_auc = metrics.auc(fpr,tpr)
roc_auc
# 绘制面积图
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.94>0.8,构建的分类器非常理想。
二、多项式贝叶斯分类器
判断蘑菇是否有毒
# 导入第三方包
import pandas as pd
# 读取数据
mushrooms = pd.read_csv(r'F:\mushrooms.csv')
# 数据的前5行
mushrooms.head(
所有字符均为字符型的离散值,做因子化处理
通过pandas模块的factorize函数,返回的是两个元素的元祖,第一个元素为转换成的数值,第二个元素为数值对应的字符水平
# 将字符型数据作因子化处理,将其转换为整数型数据
columns = mushrooms.columns[1:]
columns
for column in columns:
mushrooms[column] = pd.factorize(mushrooms[column])[0]
mushrooms.head()
拆分数据
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
# 基于训练数据集的拟合
mnb.fit(X_train, y_train)
mnb.fit
# 基于测试数据集的预测
mnb_pred = mnb.predict(X_test)
mnb_pred
# 构建混淆矩阵
cm = pd.crosstab(mnb_pred,y_test)
cm
# 绘制混淆矩阵图
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))
整体预测准确率87%,无毒蘑菇的预测覆盖率92%,有毒蘑菇的预测覆盖率82%
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()
当因变量为字符型的值时,子模块metrics中的函数roc_curve必须传入数值型的因变量,map理解为映射函数
如果自变量在特定y值下的概率不服从多项式分布,则预测效果不理想
一般多项式分类器用作文本分类的关于词语出现的次数等,例如一封邮件是否垃圾邮件,用户评论是否为正面
如果文本分类考虑词语是否会出现的0-1值,使用伯努利分类器
三、伯努利贝叶斯分类器
分析用户购买蚊帐之后评论的情绪
import pandas as pd
# 读入评论数据,sheetname指定需要读取表格中的第一个子表
evaluation = pd.read_excel(r'F:\Contents.xlsx',sheetname=0)
# 查看数据前10行
evaluation.head(10)
数据集包含4个字段,用户昵称,评价时间,评价内容,对应评价情绪
处理“脏”文本,例如数字、英文等
# 运用正则表达式,将评论中的数字和英文去除
evaluation.Content = evaluation.Content.str.replace('[0-9a-zA-Z]','')
evaluation.head(10)
下一步对文本进行切词,先要引入用户自定义的词库和停止词,利用词库的目的是将无法正常分割的词实现正常分割,例如“沙润句中金”切词为“沙”,“润”,“亲”,停止词的目的是将句中无意义的词语删除(”的“,”啊“,”我们“)
关于jieba库的用法:
#encoding=utf-8
import jieba
#全模式
text = "我来到北京清华大学"
seg_list = jieba.cut(text, cut_all=True)
print (u"[全模式]: ", "/ ".join(seg_list))
#精确模式
seg_list = jieba.cut(text, cut_all=False)
print (u"[精确模式]: ", "/ ".join(seg_list))
#默认是精确模式
seg_list = jieba.cut(text)
print (u"[默认模式]: ", "/ ".join(seg_list))
#新词识别 “杭研”并没有在词典中,但是也被Viterbi算法识别出来了
seg_list = jieba.cut("他来到了网易杭研大厦")
print (u"[新词识别]: ", "/ ".join(seg_list))
#搜索引擎模式
seg_list = jieba.cut_for_search(text)
print (u"[搜索引擎模式]: ", "/ ".join(seg_list))
回到正文:
通过调入第三方包jieba实现中文的切词,并在切词过程中加入自定义词库和删除停止词。
# 导入第三方包
import jieba
#encoding=utf-8
# 加载自定义词库
jieba.load_userdict(r'F:\1.txt')
# 读入停止词
with open(r'F:\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[:10]
利用如上的切词结果,构造文档词条矩阵,矩阵的每一行代表一个评论内容,每一列代表切词后的词语,元素为词语在文档中出现的频次。
# 导入第三方包
from sklearn.feature_extraction.text import CountVectorizer
# 计算每个词在各评论内容中的次数,并将稀疏度为99%以上的词删除
counts = CountVectorizer(min_df = 0.01)
# 文档词条矩阵
dtm_counts = counts.fit_transform(words).toarray()
dtm_counts
为了避免下面的稀疏矩阵的列数过多,在构造词条矩阵时做了相应限制,表示词语所对应的文档数目必须在所有文档中至少占1%的比例
# 矩阵的列名称
columns = counts.get_feature_names()
columns
...
# 将矩阵转换为数据框--即X变量
X = pd.DataFrame(dtm_counts, columns=columns)
X.head()
转换为数据框后是一个庞大的稀疏矩阵,大部分值为0。
# 情感标签变量
y = evaluation.Type
y
...
拆分数据集
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)
cm
# 绘制混淆矩阵图
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))
# 计算正例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()
预测效果理想。