本文的参考资料:《Python数据科学手册》;
本文的源代上传到了Gitee上;
本文用到的包:
%matplotlib inline
import pandas as pd
import seaborn as sns
from matplotlib.pylab import *
from sklearn.naive_bayes import GaussianNB, MultinomialNB
from sklearn.datasets import make_blobs, fetch_20newsgroups
from sklearn.metrics import accuracy_score, confusion_matrix
from sklearn.feature_extraction.text import TfidfVectorizer
sns.set()
plt.rc('font', family='SimHei')
plt.rc('axes', unicode_minus=False)
朴素贝叶斯分类(Naive Bayes)
朴素贝叶斯分类是一种基于贝叶斯定理的,有监督的机器学习算法,用于分类任务,通常适用于高维度的数据集,因为运行速度快、可调参数少,非常适合为分类问题提供快速粗糙的解决方案。
贝叶斯定理
P ( L ∣ 特 征 ) = P ( 特 征 ∣ L ) P ( L ) P ( 特 征 ) P(L|特征) = \frac{P(特征|L)P(L)}{P(特征)} P(L∣特征)=P(特征)P(特征∣L)P(L)
我们需要做的就是寻找一个能够计算每一个 P ( L ∣ 特 征 ) P(L|特征) P(L∣特征)的模型,这样的模型称为生成模型。
高斯朴素贝叶斯
高斯朴素贝叶斯假设每一个标签的数据都满足高斯分布,且标签之间线性无关(协方差=0),高斯朴素贝叶斯在sklearn中由GaussianNB类实现;
x_train, y_train = make_blobs(
n_samples=300,
n_features=2,
centers=2,
cluster_std=[1.5, 2.5],
random_state=2
)
fig, axs = plt.subplots(1, 2, figsize=(20, 10))
ax_train = axs[0] # type: plt.Axes
ax_test = axs[1] # type: plt.Axes
ax_train.scatter(x=x_train[:, 0], y=x_train[:, 1], c=y_train, s=25, cmap=plt.cm.get_cmap('winter', lut=2))
ax_train.set_title('训练集')
ax_train.set_xlim(-6, 6)
ax_train.set_xticks(range(-6, 6 + 1, 2))
ax_train.set_ylim(-13, 8)
ax_train.set_yticks(range(-14, 8 + 1, 2))
fig.colorbar(
mappable=plt.cm.ScalarMappable(cmap=plt.cm.get_cmap('winter', lut=2)),
ax=ax_train,
ticks=[1, 0]
)
x_test = np.zeros((2000, 2))
x_test[:, 0] = np.random.rand(2000) * 12 - 6
x_test[:, 1] = np.random.rand(2000) * 22 - 14
model = GaussianNB()
model.fit(x_train, y_train)
y_test = model.predict(x_test)
y_prob = model.predict_proba(x_test) # 每个样例属于每个标签的概率
y_size = np.zeros(2000)
y_size[y_test == 1] = (2 ** y_prob[:, 1][y_test == 1]) * 10
y_size[y_test == 0] = (2 ** y_prob[:, 0][y_test == 0]) * 10
ax_test.scatter(x=x_test[:, 0], y=x_test[:, 1], c=y_test, s=y_size, cmap=plt.cm.get_cmap('winter', lut=2))
ax_test.set_title('拟合随机数据结果')
ax_test.set_xlim(-6, 6)
ax_test.set_xticks(range(-6, 6 + 1, 2))
ax_test.set_ylim(-13, 8)
ax_test.set_yticks(range(-14, 8 + 1, 2))
fig.colorbar(
mappable=plt.cm.ScalarMappable(cmap=plt.cm.get_cmap('winter', lut=2)),
ax=ax_test,
ticks=[0, 1],
)
效果:
多项式朴素贝叶斯
多项式朴素贝叶斯假设样本中的每一个特征都是服从多项式分布的,适用于处理“出现次数”或者是“出现比例”这样的特征;
这里使用sklearn提供的英语新闻语料库来演示使用多项式贝叶斯进行文本分类(使用sklearn内置工具计算词频逆文档频率);
sklearn中,多项式朴素贝叶斯由MultinomialNB类实现;
加载训练数据并查看训练数据的情况:
text_data = fetch_20newsgroups()
print('新闻组:')
for i, j in enumerate(text_data.target_names):
print(f'{j:<25}', end=('\n' if (i + 1) % 3 == 0 else ' | '))
print('\n')
categories_selected = ['talk.religion.misc', 'soc.religion.christian', 'sci.space', 'comp.graphics'] # 需要用到的四个组
text_train = fetch_20newsgroups(subset='train', categories=categories_selected)
text_test = fetch_20newsgroups(subset='test', categories=categories_selected)
输出:
新闻组:
alt.atheism | comp.graphics | comp.os.ms-windows.misc
comp.sys.ibm.pc.hardware | comp.sys.mac.hardware | comp.windows.x
misc.forsale | rec.autos | rec.motorcycles
rec.sport.baseball | rec.sport.hockey | sci.crypt
sci.electronics | sci.med | sci.space
soc.religion.christian | talk.politics.guns | talk.politics.mideast
talk.politics.misc | talk.religion.misc |
训练模型、进行测试、输出正确率:
vec = TfidfVectorizer().fit(text_train.data)
model = MultinomialNB()
model.fit(vec.transform(text_train.data), text_train.target)
text_res = model.predict(vec.transform(text_test.data))
print(f'多项式朴素贝叶斯应用于文本分类的准确率:{accuracy_score(text_test.target, text_res) * 100:0.3f}%')
输出结果:
多项式朴素贝叶斯应用于文本分类的准确率:80.168%
使用sklearn提供的工具计算混淆矩阵,并使用seaborn进行可视化:
mat = confusion_matrix(text_test.target, text_res)
plt.figure(figsize=(10, 10))
sns.heatmap(
mat.T,
square=True,
annot=True,
fmt='d',
cbar=False,
xticklabels=text_train.target_names,
yticklabels=text_train.target_names,
cmap='Greens',
)
plt.xlabel('正确分类')
plt.ylabel('模型预测')
结果:
通过混淆矩阵可以看到,模型能够很好的分辨计算机新闻与宇宙新闻,但是不能很好的分辨宗教新闻与基督教新闻;
完整代码(Jupyter Notebook)
#%%
%matplotlib inline
import pandas as pd
import seaborn as sns
from matplotlib.pylab import *
from sklearn.naive_bayes import GaussianNB, MultinomialNB
from sklearn.datasets import make_blobs, fetch_20newsgroups
from sklearn.metrics import accuracy_score, confusion_matrix
from sklearn.feature_extraction.text import TfidfVectorizer
sns.set()
plt.rc('font', family='SimHei')
plt.rc('axes', unicode_minus=False)
#%% md
# 朴素贝叶斯分类
朴素贝叶斯分类通常适用于高维度的数据集,因为运行速度快、可调参数少,非常适合为分类问题提供快速粗糙的解决方案。
## 贝叶斯定理
$$ P(L|特征) = \frac{P(特征|L)P(L)}{P(特征)} $$
我们需要做的就是寻找一个能够计算每一个$P(L|特征)$的模型,这样的模型称为**生成模型**。
## 高斯朴素贝叶斯
高斯朴素贝叶斯假设每一个标签的数据都满足高斯分布,且标签之间线性无关(协方差=0)。
#%%
x_train, y_train = make_blobs(
n_samples=300,
n_features=2,
centers=2,
cluster_std=[1.5, 2.5],
random_state=2
)
fig, axs = plt.subplots(1, 2, figsize=(20, 10))
ax_train = axs[0] # type: plt.Axes
ax_test = axs[1] # type: plt.Axes
ax_train.scatter(x=x_train[:, 0], y=x_train[:, 1], c=y_train, s=25, cmap=plt.cm.get_cmap('winter', lut=2))
ax_train.set_title('训练集')
ax_train.set_xlim(-6, 6)
ax_train.set_xticks(range(-6, 6 + 1, 2))
ax_train.set_ylim(-13, 8)
ax_train.set_yticks(range(-14, 8 + 1, 2))
fig.colorbar(
mappable=plt.cm.ScalarMappable(cmap=plt.cm.get_cmap('winter', lut=2)),
ax=ax_train,
ticks=[1, 0]
)
x_test = np.zeros((2000, 2))
x_test[:, 0] = np.random.rand(2000) * 12 - 6
x_test[:, 1] = np.random.rand(2000) * 22 - 14
model = GaussianNB()
model.fit(x_train, y_train)
y_test = model.predict(x_test)
y_prob = model.predict_proba(x_test) # 每个样例属于每个标签的概率
y_size = np.zeros(2000)
y_size[y_test == 1] = (2 ** y_prob[:, 1][y_test == 1]) * 10
y_size[y_test == 0] = (2 ** y_prob[:, 0][y_test == 0]) * 10
ax_test.scatter(x=x_test[:, 0], y=x_test[:, 1], c=y_test, s=y_size, cmap=plt.cm.get_cmap('winter', lut=2))
ax_test.set_title('拟合随机数据结果')
ax_test.set_xlim(-6, 6)
ax_test.set_xticks(range(-6, 6 + 1, 2))
ax_test.set_ylim(-13, 8)
ax_test.set_yticks(range(-14, 8 + 1, 2))
fig.colorbar(
mappable=plt.cm.ScalarMappable(cmap=plt.cm.get_cmap('winter', lut=2)),
ax=ax_test,
ticks=[0, 1],
)
#%% md
## 多项式朴素贝叶斯
多项式朴素贝叶斯假设样本中的每一个特征都是服从多项式分布的,适用于处理“出现次数”或者是“出现比例”这样的特征;
这里使用sklearn提供的英语新闻语料库来演示使用多项式贝叶斯进行文本分类;
#%%
text_data = fetch_20newsgroups()
print('新闻组:')
for i, j in enumerate(text_data.target_names):
print(f'{j:<25}', end=('\n' if (i + 1) % 3 == 0 else ' | '))
print('\n')
categories_selected = ['talk.religion.misc', 'soc.religion.christian', 'sci.space', 'comp.graphics']
text_train = fetch_20newsgroups(subset='train', categories=categories_selected)
text_test = fetch_20newsgroups(subset='test', categories=categories_selected)
vec = TfidfVectorizer().fit(text_train.data)
model = MultinomialNB()
model.fit(vec.transform(text_train.data), text_train.target)
text_res = model.predict(vec.transform(text_test.data))
print(f'多项式朴素贝叶斯应用于文本分类的准确率:{accuracy_score(text_test.target, text_res) * 100:0.3f}%')
mat = confusion_matrix(text_test.target, text_res)
plt.figure(figsize=(10, 10))
sns.heatmap(
mat.T,
square=True,
annot=True,
fmt='d',
cbar=False,
xticklabels=text_train.target_names,
yticklabels=text_train.target_names,
cmap='Greens',
)
plt.xlabel('正确分类')
plt.ylabel('模型预测')
#%% md
通过混淆矩阵可以看到,模型能够很好的分辨计算机新闻与宇宙新闻,但是不能很好的分辨宗教新闻与基督教新闻;