朴素贝叶斯模型
4.1 朴素贝叶斯模型
P ( C ∣ F 1 , F 2 , . . . , F n ) = P ( F 1 , F 2 , . . . , F n ∣ C ) ∗ P ( C ) P ( F 1 , F 2 , . . . , F n ) P(C|F_1,F_2,...,F_n)=\frac{P(F_1,F_2,...,F_n|C)*P(C)}{P(F_1,F_2,...,F_n)} P(C∣F1,F2,...,Fn)=P(F1,F2,...,Fn)P(F1,F2,...,Fn∣C)∗P(C)
= P ( F 1 ∣ C ) ∗ P ( F 2 ∣ C ) ∗ . . . ∗ P ( F n ∣ C ) ∗ P ( C ) P ( F 1 , F 2 , . . . , F n ) =\frac{P(F_1|C)*P(F_2|C)*...*P(F_n|C)*P(C)}{P(F_1,F_2,...,F_n)} =P(F1,F2,...,Fn)P(F1∣C)∗P(F2∣C)∗...∗P(Fn∣C)∗P(C)
拉普拉斯平滑系数
P ( F 1 ∣ C ) = n i + a n + a m P(F_1|C)=\frac{n_i+a}{n+am} P(F1∣C)=n+amni+a
朴素⻉叶斯优缺点:
- 优点
a.朴素⻉叶斯模型发源于古典数学理论,有稳定的分类效率;b.对缺失数据不太敏感,算法也比较简;c.常用于文本分类分类准确度高,速度快.
- 缺点
a.由于使用了样本属性独立性的假设,所以如果特征属性有关联时其效果不好; b.需要计算先验概率,而先验概率很多时候取决于假设,假设的模型可以有很多种,因此在某些时候会由于假设的先验模型的原因导致预测效果不佳
4.2 模型参数估计
import numpy as np
class BernoulliNavieBayes:
def __init__(self, alpha=1.):
self.alpha = alpha # 平滑系数
def _class_prior_proba_log(self, y, classes):
'''计算所有类别先验概率P(y=c_k)'''
c_count = np.count_nonzero(y == classes[:, None], axis=1) # 统计各类别样本数量c_count =[0:5,1:5]
p = (c_count + self.alpha) / (len(y) + len(classes) * self.alpha) # 计算各类别先验概率(平滑修正)p[0.5,0.5]
return np.log(p)
def _conditional_proba_log(self, X, y, classes):
'''计算所有条件概率P(x^(j)|y=c_k)的对数'''
_, n = X.shape # [10,3]
cls_num = len(classes) # k=2
# P_log: 2个条件概率的对数的矩阵
# 矩阵P_log[0]存储所有log(P(x^(j)=0|y=c_k))
# 矩阵P_log[1]存储所有log(P(x^(j)=1|y=c_k))
P_log = np.empty((2, cls_num, n)) # [2,2,3] 2(是,不是), K(y1,y2,...,yk), n(x1,x2,...,xn)
# 迭代每一个类别c_k
for indx, cls in enumerate(classes): # k,c=0,0
# 获取类别为c_k的实例
X_c = X[y == cls]
# 统计各特征值为1的实例的数量
count1 = np.count_nonzero(X_c, axis=0) # count1=[3,2,1]
# 计算条件概率P(x^(j)=1|y=c_k)(平滑修正)
p1 = (count1 + self.alpha) / (len(X_c) + 2 * self.alpha)
# 将log(P(x^(j)=0|y=c_k))和log(P(x^(j)=1|y=c_k))存入矩阵
P_log[0, indx] = np.log(1 - p1)
P_log[1, indx] = np.log(p1)
return P_log
def train(self, X_train, y_train):
'''训练模型'''
# 获取所有类别
self.classes = np.unique(y_train) # classes [0,1]
# 计算并保存所有先验概率的对数
self.pp_log = self._class_prior_proba_log(y_train, self.classes)
# 计算并保存所有条件概率的对数
self.cp_log = self._conditional_proba_log(X_train, y_train, self.classes)
def _predict(self, x):
'''对单个实例进行预测'''
K = len(self.classes)
p_log = np.empty(K)
# 分别获取各特征值为1和0的索引
idx1 = x == 1
idx0 = ~idx1
# 迭代每一个类别c_k
for k in range(K):
# 计算后验概率P(c_k|x)分子部分的对数. x=[1,1,0]
p_log[k] = self.pp_log[k] + np.sum(self.cp_log[0, k][idx0]) \
+ np.sum(self.cp_log[1, k][idx1])
# 返回具有最大后验概率的类别
return np.argmax(p_log)
def predict(self, X):
'''预测'''
# 对X中每个实例, 调用_predict进行预测, 收集结果并返回.
return np.apply_along_axis(self._predict, axis=1, arr=X)
if __name__ == '__main__':
X = np.array([[1,0,1],[1,1,0],[1,1,1],[0,1,1],[0,0,1],[1,0,1],[1,1,0],[0,1,0],[0,0,0],[1,0,0]])
y = np.array([1,1,1,1,1,0,0,0,0,0])
Byes = BernoulliNavieBayes()
Byes.train(X,y)
y_pre = Byes.predict(X)
print('Results:',y_pre)
'''
Results: [1 0 1 1 1 1 0 0 0 0]
Process finished with exit code 0
'''