本系列所有的代码和数据都可以从陈强老师的个人主页上下载:Python数据程序
参考书目:陈强.机器学习及Python应用. 北京:高等教育出版社, 2021.
本系列基本不讲数学原理,只从代码角度去让读者们利用最简洁的Python代码实现机器学习方法。
贝叶斯也是经典的统计学方法,机器学习里面的贝叶斯也是基于条件概率和全概率去判断响应变量的类别。而机器学习里面的朴素贝叶斯是具有很强的独立性假设,即特征变量每个分量属性之间是条件独立的。这个假设条件非常强,因此也被称为“朴素”的贝叶斯。
导入包和读取数据
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB
from sklearn.naive_bayes import MultinomialNB
from sklearn.naive_bayes import ComplementNB
from sklearn.naive_bayes import BernoulliNB
from sklearn.metrics import cohen_kappa_score
from sklearn.metrics import plot_roc_curve
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import GridSearchCV
spam = pd.read_csv('spam.csv')
spam.shape
数据形状为4601,58,说明有4601个样本,57个特征变量x,和一个响应变量y。
print(spam.spam.value_counts())
spam.spam.value_counts(normalize=True) #百分比计算
计算响应变量y的取值种类和数量
其中电子邮件为2788个,垃圾邮件为1813个。
选前五个特征变量画出频率直方图:
spam.iloc[:, :5].plot.hist(subplots=True, bins=100)
因为是文本数据,所以很多文章里面的部分词汇是没有出现的,数据高度稀疏。下面开始机器学习!
取出X和y,划分训练集和测试集
X = spam.iloc[:, :-1]
y = spam.iloc[:, -1]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, stratify=y, random_state=0)
生成朴素贝叶斯类,进行拟合,在训练集上测评
model = GaussianNB()
model.fit(X_train, y_train)
model.score(X_test, y_test)
多项朴素贝叶斯
model = MultinomialNB(alpha=0)
model.fit(X_train, y_train)
model.score(X_test, y_test)
采用拉普拉斯修正的多项朴素贝叶斯
model = MultinomialNB(alpha=1) # Laplacian Correction
model.fit(X_train, y_train)
model.score(X_test, y_test)
互补朴素贝叶斯
model = ComplementNB(alpha=1)
model.fit(X_train, y_train)
model.score(X_test, y_test)
二项朴素贝叶斯(伯努利)
model = BernoulliNB(alpha=1)
model.fit(X_train, y_train)
model.score(X_test, y_test)
设置二项分布的阈值为0.1
model = BernoulliNB(binarize=0.1, alpha=1)
model.fit(X_train, y_train)
model.score(X_test, y_test)
使用手动网格化找最优超参数
best_score = 0
for binarize in np.arange(0, 1.1, 0.1):
for alpha in np.arange(0, 1.1, 0.1):
model = BernoulliNB(binarize=binarize, alpha=alpha)
model.fit(X_train, y_train)
score = model.score(X_test, y_test)
if score > best_score:
best_score = score
best_parameters = {'binarize': binarize, 'alpha': alpha}
best_score
best_parameters
结果显示了最优的超参数。下面将最优的参数传入模型进行拟合和测试评价。
model = BernoulliNB(**best_parameters)
model.fit(X_trainval, y_trainval)
model.score(X_test, y_test)
或者采用GridSearchCV去自动搜索最优超参数。
param_grid = {'binarize': np.arange(0, 1.1, 0.1), 'alpha': np.arange(0, 1.1, 0.1)}
model = GridSearchCV(BernoulliNB(), param_grid, cv=kfold)
model.fit(X_train, y_train)
#测试集评分
model.score(X_test, y_test)
#模型最优参数
model.best_params_
#验证时最优评分
model.best_score_ # best cross validation accuracy
#最好的估计器
model.best_estimator_
#获取每个交叉验证的详细信息,变为数据框
results = pd.DataFrame(model.cv_results_)
results.head(2)
包括了10个子样本的预测准确率,评价准确率等。取出平均准确率进行热力图可视化:
scores = np.array(results.mean_test_score).reshape(11,11)
ax = sns.heatmap(scores, cmap='Blues', annot=True, fmt='.3f')
ax.set_xlabel('binarize')
ax.set_xticklabels([0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1])
ax.set_ylabel('alpha')
ax.set_yticklabels([0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1])
plt.tight_layout()
可见binarize取0.1和0.2最好,而alpha则无明显影响。
模型拟合完要进行评价,分类问题一般都采用混淆矩阵评价。
首先预测,得到预测值pred,和真实值y_test进行混淆矩阵比较。
#预测概率
prob = model.predict_proba(X_test)
#预测类别
pred = model.predict(X_test)
#数据透视表,混淆矩阵
table = pd.crosstab(y_test, pred, rownames=['Actual'], colnames=['Predicted'])
table
计算其混淆矩阵的指标
table = np.array(table)
Accuracy = (table[0, 0] + table[1, 1]) / np.sum(table)
Accuracy #准确率
Error_rate = 1 - Accuracy
Error_rate #错误率
Sensitivity = table[1, 1]/(table[1, 0] + table[1, 1])
Sensitivity # 敏感度
Specificity = table[0, 0] / (table[0, 0] + table[0, 1])
Specificity #特异度
Recall = table[1, 1] / (table[0, 1] + table[1, 1])
Recall #召回率
cohen_kappa_score(y_test, pred) #科恩指标
画ROC曲线
plot_roc_curve(model, X_test, y_test)
x = np.linspace(0, 1, 100)
plt.plot(x, x,'k--', linewidth=1)
plt.title('ROC Curve for Bernoulli Naive Bayes')
#或者可以这样画
from sklearn.metrics import RocCurveDisplay
RocCurveDisplay.from_estimator(model, X_test, y_test)
#RocCurveDisplay.from_predictions(y_test,pred)
#还可以这样画
from scikitplot.metrics import plot_roc
plot_roc(y_test, prob)
x = np.linspace(0, 1, 100)
plt.plot(x, x, 'k--', linewidth=1)
plt.title('ROC Curve (Test Set)')
和上一章一样,用鸢尾花数据集选两个特征变量,画出朴素贝叶斯的决策边界:
from sklearn.datasets import load_iris
from mlxtend.plotting import plot_decision_regions
X, y = load_iris(return_X_y=True)
X2 = X[:, 2:4]
model = GaussianNB()
model.fit(X2, y)
model.score(X2, y)
plot_decision_regions(X2, y, model)
plt.xlabel('petal_length')
plt.ylabel('petal_width')
plt.title('Decision Boundary for Gaussian Naive Bayes')
决策边界非线性,椭圆形