朴素贝叶斯应用场景
在文本分类中,假设我们有一个文档d∈X,X是文档向量空间(document space),和一个固定的类集合C={c1,c2,…,cj},类别又称为标签。
显然,文档向量空间是一个高维度空间。我们把一堆打了标签的文档集合<d,c>作为训练样本,<d,c>∈X×C。例如:<d,c>={Beijing joins the World Trade Organization, China}
对于这个只有一句话的文档,我们把它归类到 China,即打上china标签。我们期望用某种训练算法,训练出一个函数γ,能够将文档映射到某一个类别:γ:X→C
多项式贝叶斯
在多项式模型中, 设某文档d=(t1,t2,…,tk),tk是该文档中出现过的单词,允许重复,则
先验概率P(c)= 类c下单词总数/整个训练样本的单词总数
类条件概率P(tk|c)=(类c下单词tk在各个文档中出现过的次数之和+1)/(类c下单词总数+|V|)
V是训练样本的单词表(即抽取单词,单词出现多次,只算一个),|V|则表示训练样本包含多少种单词。在这里,m=|V|, p=1/|V|。
P(tk|c)可以看作是单词tk在证明d属于类c上提供了多大的证据,而P(c)则可以认为是类别c在整体上占多大比例(有多大可能性)。
伯努利模型
伯努利模型跟多项式模型的差别在计算公式不同:
P(c)= 类c下文件总数/整个训练样本的文件总数
P(tk|c)=(类c下包含单词tk的文件数+1)/(类c的文档总数+2)
二者的计算粒度不一样,多项式模型以单词为粒度,伯努利模型以文件为粒度,因此二者的先验概率和类条件概率的计算方法都不同。
计算后验概率时,对于一个文档d,多项式模型中,只有在d中出现过的单词,才会参与后验概率计算,伯努利模型中,没有在d中出现,但是在全局单词表中出现的单词,也会参与计算,不过是作为“反方”参与的。
高斯模型
有些特征可能是连续型变量,比如说人的身高,物体的长度,这些特征如果使用决策树那些模型,可以转换成离散型的值,比如如果身高在160cm以下,特征值为1;在160cm和170cm之间,特征值为2;在170cm之上,特征值为3。也可以这样转换,将身高转换为3个特征,分别是f1、f2、f3,如果身高是160cm以下,这三个特征的值分别是1、0、0,若身高在170cm之上,这三个特征的值分别是0、0、1。
不过这些方式都不够细腻,高斯模型可以解决这个问题。高斯模型假设这些一个特征的所有属于某个类别的观测值符合高斯分布:
μ:获取各个类标记在各个特征上的均值
σ:获取各个类标记在各个特征上的方差
代码实现
高斯贝叶斯
# 加载模型 model = GaussianNB() # 训练模型 model.fit(X_train,y_train) # 预测值 y_pred = model.predict(X_test) ''' 评估指标 ''' # 求出预测和真实一样的数目 true = np.sum(y_pred == y_test ) print('预测对的结果数目为:', true) print('预测错的的结果数目为:', y_test.shape[0]-true) # 评估指标 from sklearn.metrics import accuracy_score,precision_score,recall_score,f1_score,cohen_kappa_score print('预测数据的准确率为: {:.4}%'.format(accuracy_score(y_test,y_pred)*100)) print('预测数据的精确率为:{:.4}%'.format( precision_score(y_test,y_pred)*100)) print('预测数据的召回率为:{:.4}%'.format( recall_score(y_test,y_pred)*100)) # print("训练数据的F1值为:", f1score_train) print('预测数据的F1值为:', f1_score(y_test,y_pred)) print('预测数据的Cohen’s Kappa系数为:', cohen_kappa_score(y_test,y_pred)) # 打印分类报告 from sklearn.metrics import classification_report print('预测数据的分类报告为:','\n', classification_report(y_test,y_pred))
ROC曲线和AUC面积
from sklearn.metrics import precision_recall_curve from sklearn import metrics # 预测正例的概率 y_pred_prob=model.predict_proba(X_test)[:,1] # y_pred_prob ,返回两列,第一列代表类别0,第二列代表类别1的概率 #https://blog.csdn.net/dream6104/article/details/89218239 fpr, tpr, thresholds = metrics.roc_curve(y_test,y_pred_prob, pos_label=2) #pos_label,代表真阳性标签,就是说是分类里面的好的标签,这个要看你的特征目标标签是0,1,还是1,2 roc_auc = metrics.auc(fpr, tpr) #auc为Roc曲线下的面积 # print(roc_auc) plt.figure(figsize=(8,6)) plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--') plt.plot(fpr, tpr, 'r',label='AUC = %0.2f'% roc_auc) plt.legend(loc='lower right') # plt.plot([0, 1], [0, 1], 'r--') plt.xlim([0, 1.1]) plt.ylim([0, 1.1]) plt.xlabel('False Positive Rate') #横坐标是fpr plt.ylabel('True Positive Rate') #纵坐标是tpr plt.title('Receiver operating characteristic example') plt.show()
对于高斯贝叶斯模型的参数,一般是不需要进行调参的,使用该模型一般在数据集以及特征方面进行改进
通过模型进行选择重要的特征:9个,用于预测
from sklearn.model_selection import train_test_split,cross_val_score #拆分训练集和测试集 import lightgbm as lgbm #轻量级的高效梯度提升树 X_name=df.corr()[["n23"]].sort_values(by="n23",ascending=False).iloc[1:].index.values.astype("U") X=df.loc[:,X_name.tolist()] y=df.loc[:,['n23']] X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.2,stratify=y,random_state=1) lgbm_reg = lgbm.LGBMRegressor(objective='regression',max_depth=6,num_leaves=25,learning_rate=0.005,n_estimators=1000,min_child_samples=80, subsample=0.8,colsample_bytree=1,reg_alpha=0,reg_lambda=0) lgbm_reg.fit(X_train, y_train) #选择最重要的20个特征,绘制他们的重要性排序图 lgbm.plot_importance(lgbm_reg, max_num_features=9) ##也可以不使用自带的plot_importance函数,手动获取特征重要性和特征名,然后绘图 feature_weight = lgbm_reg.feature_importances_ feature_name = lgbm_reg.feature_name_ feature_sort = pd.Series(data = feature_weight ,index = feature_name) feature_sort = feature_sort.sort_values(ascending = False) # plt.figure(figsize=(10,8)) # sns.barplot(feature_sort.values,feature_sort.index, orient='h') lgbm_name=feature_sort.index[:9].tolist() lgbm_name
X=df.loc[:,lgbm_name] y=df.iloc[:,-1] X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.2,stratify=y,random_state=1) # 加载模型 model = GaussianNB() # 训练模型 model.fit(X_train,y_train) # 预测值 y_pred = model.predict(X_test) ''' 评估指标 ''' # 求出预测和真实一样的数目 true = np.sum(y_pred == y_test ) print('预测对的结果数目为:', true) print('预测错的的结果数目为:', y_test.shape[0]-true) # 评估指标 from sklearn.metrics import accuracy_score,precision_score,recall_score,f1_score,cohen_kappa_score print('预测数据的准确率为: {:.4}%'.format(accuracy_score(y_test,y_pred)*100)) print('预测数据的精确率为:{:.4}%'.format( precision_score(y_test,y_pred)*100)) print('预测数据的召回率为:{:.4}%'.format( recall_score(y_test,y_pred)*100)) # print("训练数据的F1值为:", f1score_train) print('预测数据的F1值为:', f1_score(y_test,y_pred)) print('预测数据的Cohen’s Kappa系数为:', cohen_kappa_score(y_test,y_pred)) # 打印分类报告 from sklearn.metrics import classification_report print('预测数据的分类报告为:','\n', classification_report(y_test,y_pred))
from sklearn.metrics import precision_recall_curve from sklearn import metrics # 预测正例的概率 y_pred_prob=model.predict_proba(X_test)[:,1] # y_pred_prob ,返回两列,第一列代表类别0,第二列代表类别1的概率 #https://blog.csdn.net/dream6104/article/details/89218239 fpr, tpr, thresholds = metrics.roc_curve(y_test,y_pred_prob, pos_label=2) #pos_label,代表真阳性标签,就是说是分类里面的好的标签,这个要看你的特征目标标签是0,1,还是1,2 roc_auc = metrics.auc(fpr, tpr) #auc为Roc曲线下的面积 # print(roc_auc) plt.figure(figsize=(8,6)) plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--') plt.plot(fpr, tpr, 'r',label='AUC = %0.2f'% roc_auc) plt.legend(loc='lower right') # plt.plot([0, 1], [0, 1], 'r--') plt.xlim([0, 1.1]) plt.ylim([0, 1.1]) plt.xlabel('False Positive Rate') #横坐标是fpr plt.ylabel('True Positive Rate') #纵坐标是tpr plt.title('Receiver operating characteristic example') plt.show()
结果展示:
果不其然,通过了特征选取的方式,模型的效果有了一定的改善,这里你也可以结合之前的博客文章:
机器学习框架及评估指标详解
特征选取之单变量统计、基于模型选择、迭代选择
将所有的指标都可以进行探究最后通过特征选取等方法,去增加模型的指标
其他模型尝试
多项式贝叶斯
适用于服从多项分布的特征数据
class sklearn.naive_bayes.MultinomialNB(alpha=1.0, fit_prior=True, class_prior=None)
alpha:先验平滑因子,默认等于1,当等于1时表示拉普拉斯平滑。
fit_prior:是否去学习类的先验概率,默认是True
class_prior:各个类别的先验概率,如果没有指定,则模型会根据数据自动学习, 每个类别的先验概率相同,等于类标记总个数N分之一。
class_log_prior_:每个类别平滑后的先验概率
intercept_:是朴素贝叶斯对应的线性模型,其值和class_log_prior_相同
feature_log_prob_:给定特征类别的对数概率(条件概率)。 特征的条件概率=(指定类下指定特征出现的次数+alpha)/(指定类下所有特征出现次数之和+类的可能取值个数*alpha)
coef_: 是朴素贝叶斯对应的线性模型,其值和feature_log_prob相同
class_count_: 训练样本中各类别对应的样本数
feature_count_: 每个类别中各个特征出现的次数
伯努利朴素贝叶斯
用于多重伯努利分布的数据,即有多个特征,但每个特征都假设是一个二元 (Bernoulli, boolean) 变量
class sklearn.naive_bayes.BernoulliNB(alpha=1.0, binarize=0.0, fit_prior=True, class_prior=None)
alpha:平滑因子,与多项式中的alpha一致。
binarize:样本特征二值化的阈值,默认是0。如果不输入,则模型会认为所有特征都已经是二值化形式了;如果输入具体的值,则模型会把大于该值的部分归为一类,小于的归为另一类。
fit_prior:是否去学习类的先验概率,默认是True
class_prior:各个类别的先验概率,如果没有指定,则模型会根据数据自动学习, 每个类别的先验概率相同,等于类标记总个数N分之一。
class_log_prior_:每个类别平滑后的先验对数概率。
feature_log_prob_:给定特征类别的经验对数概率。
class_count_:拟合过程中每个样本的数量。
feature_count_:拟合过程中每个特征的数量。
这些都是可以通过尝试进行探索,总的来说,纸上得来终觉浅,绝知此事要躬行。
优点缺点、参数总结
MultinomialNB 和 BernoulliNB 都只有一个参数 alpha,用于控制模型复杂度。
alpha 的工作原理是,算法向数据中添加 alpha 这么多的虚拟数据点,这些点对所有特征都取正值。这可以将统计数据“平滑化”(smoothing)。 alpha 越大,平滑化越强,模型复杂度就越低。
算法性能对 alpha 值的鲁棒性相对较好,也就是说, alpha 值对模型性能并不重要。但调整这个参数通常都会使精度略有提高。
GaussianNB 主要用于高维数据,而另外两种朴素贝叶斯模型则广泛用于稀疏计数数据,比
如文本。
MultinomialNB 的性能通常要优于 BernoulliNB,特别是在包含很多非零特征的数据集(即大型文档)上。朴素贝叶斯模型的许多优点和缺点都与线性模型相同。它的训练和预测速度都很快,训练
过程也很容易理解。
该模型对高维稀疏数据的效果很好,对参数的鲁棒性也相对较好。朴素贝叶斯模型是很好的基准模型,常用于非常大的数据集,在这些数据集上即使训练线性模型可能也要花费大量时间。