本篇对应全书第四章,讲的是朴素贝叶斯法。朴素贝叶斯(Naive Bayes)是基于贝叶斯定理与特征条件独立假设的分类方法。对于给定的训练数据集,首先基于特征条件独立假设学习输入/输出的联合概率分布;然后基于此模型,对给定的输入 ,利用贝叶斯定理求出后验概率最大的输出 。
1、理论讲解
1.1、模型原理
设输入空间
为
维向量的集合,输出空间为类标记集合
。输入为特征向量
,输出为类标记
。
是定义在输入空间
上的随机向量,
是定义在输出空间
上的随机变量。
是
和
的联合概率分布。训练集
由
独立同分布产生。
朴素贝叶斯通过训练集学习联合概率分布
。具体地,学习以下先验概率分布及条件概率分布。先验概率分布:
条件概率分布:
于是学习到联合概率分布
。
朴素贝叶斯对条件概率分布作了条件独立性的假设,即用于分类的特征在类确定的条件下都是条件独立的。由于这是一个较强的假设,朴素贝叶斯法也由此得名。具体地,条件独立性假设是:
这一假设使模型变得简单,但有时会牺牲一定的分类准确率。
朴素贝叶斯分类时,对给定的输入
,通过学习到的模型计算后验概率分布
,将后验概率最大的类输出:
此处,后验概率最大化的本质是0-1损失函数下的期望风险最小化。
1.2、参数估计
在朴素贝叶斯中,学习意味着估计 和 ,既可以采用极大似然估计也可以采用贝叶斯估计。
1.2.1、极大似然估计
先验概率
的极大似然估计:
设第
个特征
可能取值的集合为
,条件概率
的极大似然估计:
其中,
是第
个样本的第
个特征;
是第
个特征可能取的第
个值。
1.2.2、贝叶斯估计
用极大似然估计可能会出现所要估计的概率值为0的情况。这时会影响到后验概率的计算结果,使分类产生偏差。解决这一问题的方法是采用贝叶斯估计。
先验概率
的贝叶斯估计:
条件概率
的贝叶斯估计:
其中,
,当
时,就是极大似然估计。常取
,这时称为拉普拉斯平滑。
1.3、小结
- 朴素贝叶斯是典型的生成学习方法;
- 由于条件独立性假设,朴素贝叶斯高效且易于实现,但也因此损失了分类性能;
- 如果输入特征彼此存在概率依存关系,即没有条件独立性假设,模型就变成了贝叶斯网络;
- 实际应用中,对应于条件概率分布 所做的不同假设,朴素贝叶斯有三种模型:高斯模型、多项式模型和伯努利模型。高斯模型常应用于特征连续的情况中,多项式模型和伯努利模型常应用于文本分类中。读者可阅读参考文献详细了解。
2、代码实现
2.1、手工实现
from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from collections import Counter
class GaussianNB:
def __init__(self, X_train, y_train):
self.X_train = X_train
self.y_train = y_train
self.get_params()
def get_params(self):
samples_num = len(self.y_train)
label_count = Counter(self.y_train).items()
self.class_ = np.array([_[0] for _ in label_count])
self.class_count_ = np.array([_[1] for _ in label_count])
self.class_prior_ = self.class_count_/samples_num
sample_split = [self.X_train[self.y_train == _] for _ in self.class_]
self.theta_ = np.array([np.transpose(_).mean(axis = 1) for _ in sample_split])
self.sigma_ = np.array([np.transpose(_).var(axis = 1) for _ in sample_split])
def gaussian_func(self, X):
prob_list = []
for theta, sigma, prior in zip(self.theta_, self.sigma_, self.class_prior_):
prob_ = np.prod(1/np.sqrt(2 * np.pi * sigma) * np.exp(-np.square(X - theta)/(2 * sigma))) * prior
prob_list.append(prob_)
return np.array(prob_list)
def predict(self, X_test):
label_list = []
for X in X_test:
prob_list = self.gaussian_func(X)
label = self.class_[np.argmax(prob_list)]
label_list.append(label)
return np.array(label_list)
def score(self, X_test, y_test):
total_num = len(X_test)
pre = (self.predict(X_test) == y_test).sum()
score = pre/total_num
return score
if __name__ == "__main__":
iris = load_iris()
X = iris.data[:100, :2]
y = iris.target[:100]
y[y == 0] = -1
xlabel = iris.feature_names[0]
ylabel = iris.feature_names[1]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)
X_0 = X_train[y_train == -1]
X_1 = X_train[y_train == 1]
plt.figure("nb-mine")
plt.scatter(X_0[:, 0], X_0[:, 1], label = '-1')
plt.scatter(X_1[:, 0], X_1[:, 1], label = '1')
plt.xlabel(xlabel)
plt.ylabel(ylabel)
plt.legend()
clf = GaussianNB(X_train, y_train)
score = clf.score(X_test, y_test)
print "score : %s" % score
y_pre = clf.predict(X_test)
X_test_pre_0 = X_test[y_pre == -1]
X_test_pre_1 = X_test[y_pre == 1]
plt.scatter(X_test_pre_0[:, 0], X_test_pre_0[:, 1], color = 'r', label = 'pre -1')
plt.scatter(X_test_pre_1[:, 0], X_test_pre_1[:, 1], color = 'k', label = 'pre 1')
plt.legend()
plt.show()
2.2、sklearn实现
from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import train_test_split
if __name__ == "__main__":
iris = load_iris()
X = iris.data[:100, :2]
y = iris.target[:100]
y[y == 0] = -1
xlabel = iris.feature_names[0]
ylabel = iris.feature_names[1]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)
X_0 = X_train[y_train == -1]
X_1 = X_train[y_train == 1]
plt.figure("GaussianNB-sklearn")
plt.scatter(X_0[:, 0], X_0[:, 1], label = '-1')
plt.scatter(X_1[:, 0], X_1[:, 1], label = '1')
plt.xlabel(xlabel)
plt.ylabel(ylabel)
plt.legend()
clf = GaussianNB()
clf.fit(X_train, y_train)
score = clf.score(X_test, y_test)
print "score : %s" % score
y_pre = clf.predict(X_test)
X_test_pre_0 = X_test[y_pre == -1]
X_test_pre_1 = X_test[y_pre == 1]
plt.scatter(X_test_pre_0[:, 0], X_test_pre_0[:, 1], color = 'r', label = 'pre -1')
plt.scatter(X_test_pre_1[:, 0], X_test_pre_1[:, 1], color = 'k', label = 'pre 1')
plt.legend()
plt.show()
代码已上传至github:https://github.com/xiongzwfire/statistical-learning-method
#参考文献
[1] http://scikit-learn.org/stable/modules/naive_bayes.html
[2] https://www.letiantian.me/2014-10-12-three-models-of-naive-nayes/
以上为本文全部参考文献,对原作者表示感谢。