核心思想:
根据训练数据获取模型的后验概率,对应后验概率越大的类即预测类。
算法简介:
模型:
- 先验概率:
- 条件概率:
- 后验概率:
$
朴素的含义:输入向量x的各个维度间是相互独立的,那么条件概率的计算公式可以大大简化
根据贝叶斯定理:
策略
统计机器学习的策略通常是期望风险最小化,实际学习过程中以经验风险近似期望风险(或加上正则化项)。在朴素贝叶斯方法中,期望风险最小化等价于后验概率最大化(具体推导过程参考李航《统计学习方法》)。
学习方法(模型的参数估计):
模型中后验概率的计算需要先获取先验概率以及条件概率分布,这两个概率的参数是通过训练数据集学习得到的,具体的学习方法有:极大似然估计以及后验期望估计。极大似然估计等同于先验分布为均匀分布的后验期望估计(具体参看上一篇博客)。具体公式参考李航《统计学习方法》。注意:书中参数的贝叶斯估计就是先验分布为均匀分布的后验期望估计。
算法流程
- Input: 训练数据集X, y
- Output: 每个类和,每个维度上取值的联合概率
- Step1: 采用后验期望估计方法估计后验概率
- Step2: 采用后验期望估计方法估计条件概率
- Step3:根据Step1, 2结果,计算联合分布概率
代码
"""
朴素贝叶斯分类算法
采用后验期望估计参数,先验概率分布取均匀分布
"""
from collections import Counter, defaultdict
import numpy as np
class NBayes:
def __init__(self, lambda_=1):
self.lambda_ = lambda_ # 贝叶斯估计方法参数lambda
self.p_prior = {} # 模型的先验概率, 注意这里的先验概率不是指预先人为设定的先验概率,而是需要估计的P(y=Ck)
self.p_condition = {} # 模型的条件概率
def fit(self, X_data, y_data):
N = y_data.shape[0]
# 后验期望估计P(y=Ck)的后验概率,设定先验概率为均匀分布
c_y = Counter(y_data)
K = len(c_y)
for key, val in c_y.items():
self.p_prior[key] = (val + self.lambda_) / (N + K * self.lambda_)
# 后验期望估计P(Xd=a|y=Ck)的后验概率,同样先验概率为均匀分布
for d in range(X_data.shape[1]): # 对各个维度分别进行处理
Xd_y = defaultdict(int)
vector = X_data[:, d]
Sd = len(np.unique(vector))
for xd, y in zip(vector, y_data): # 这里Xd仅考虑出现在数据集D中的情况,故即使用极大似然估计叶没有概率为0的情况
Xd_y[(xd, y)] += 1
for key, val in Xd_y.items():
self.p_condition[(d, key[0], key[1])] = (val + self.lambda_) / (c_y[key[1]] + Sd * self.lambda_)
return
def predict(self, X):
p_post = defaultdict()
for y, py in self.p_prior.items():
p_joint = py # 联合概率分布
for d, Xd in enumerate(X):
p_joint *= self.p_condition[(d, Xd, y)] # 条件独立性假设
p_post[y] = p_joint # 分母P(X)相同,故直接存储联合概率分布即可
return max(p_post, key=p_post.get)
if __name__ == '__main__':
data = np.array([[1, 0, -1], [1, 1, -1], [1, 1, 1], [1, 0, 1],
[1, 0, -1], [2, 0, -1], [2, 1, -1], [2, 1, 1],
[2, 2, 1], [2, 2, 1], [3, 2, 1], [3, 1, 1],
[3, 1, 1], [3, 2, 1], [3, 2, -1]])
X_data = data[:, :-1]
y_data = data[:, -1]
clf = NBayes(lambda_=1)
clf.fit(X_data, y_data)
print(clf.p_prior, '\n', clf.p_condition)
print(clf.predict(np.array([2, 0])))