模型定位:朴素贝叶斯属于分类模型、生成模型
GitHub地址
思路:在分类问题中,给定特征x,想知道x对应的类别y是什么。根据前述基本概念可知,后验概率计算的结果就是给定条件x,Y=yi的概率。假设有k个类别: y i , i = 1 , . . . , k y_i,i=1,...,k yi,i=1,...,k,计算每个yi对应的后验概率 P ( Y = y i ∣ X = x ) P(Y=y_i|X=x) P(Y=yi∣X=x),后验概率最大的yi就是我们求得的结果。
当 X ⊆ R n , n > 1 X\subseteq{R^n},n>1 X⊆Rn,n>1时,条件概率 P ( X = ( x 1 , x 2 , . . . , x n ) ∣ Y = y i ) P(X=(x_1,x_2,...,x_n)|Y=y_i) P(X=(x1,x2,...,xn)∣Y=yi)将随着n指数增长。因此,朴素贝叶斯对条件概率分布做了条件独立性假设: P ( X = ( x 1 , x 2 , . . . , x n ) ∣ Y = y i ) = ∏ j = 1 n P ( X j = x i j Y = y i ) P(X=(x_1,x_2,...,x_n)|Y=y_i)=\prod_{j=1}^{n}P(X_j=x_ijY=y_i) P(X=(x1,x2,...,xn)∣Y=yi)=∏j=1nP(Xj=xijY=yi),这也是朴素贝叶斯名称的由来。
所以,朴素贝叶斯分类器可以表示为: y = f ( x ) = arg max y i P ( Y = y i ) ∗ ∏ i = j = 1 n P ( X j = x j ∣ Y = y j ) ∑ i = 1 k P ( Y = y i ) ∗ ∏ i = j = 1 n P ( X j = x j ∣ Y = y i ) y=f(x)=\argmax_{y_i}\frac{P(Y=y_i)*\prod_{i=j=1}^{n}P(X_j=x_j|Y=y_j)}{\sum_{i=1}^kP(Y=y_i)*\prod_{i=j=1}^{n}P(X_j=x_j|Y=y_i)} y=f(x)=yiargmax∑i=1kP(Y=yi)∗∏i=j=1nP(Xj=xj∣Y=yi)P(Y=yi)∗∏i=j=1nP(Xj=xj∣Y=yj)
此外,给定x,分母 P ( X = x ) = ∑ i = 1 k P ( Y = y i ) ∗ ∏ i = j = 1 n P ( X j = x j ∣ Y = y i ) P(X=x)=\sum_{i=1}^kP(Y=y_i)*\prod_{i=j=1}^{n}P(X_j=x_j|Y=y_i) P(X=x)=∑i=1kP(Y=yi)∗∏i=j=1nP(Xj=xj∣Y=yi)对所有yi都是一样的,因此,在计算时,只需求解 y ~ = arg max y i P ( Y = y i ) ∗ ∏ i = j = 1 n P ( X j = x j ∣ Y = y j ) \widetilde{y}=\argmax_{y_i}P(Y=y_i)*\prod_{i=j=1}^{n}P(X_j=x_j|Y=y_j) y =yiargmaxP(Y=yi)∗∏i=j=1nP(Xj=xj∣Y=yj)即可。
!!后验概率最大化 等于 期望风险最小化【证明略】
!!本质是学习了X和Y的联合分布
极大似然估计的通俗解释:当样本数趋于无穷时,频率趋近于概率
这里使用pandas的Dataframe格式,目的是避免for循环
'''
author : superpig99
date : 2021/12/11
'''
import pandas as pd
class naiveBayes:
def __init__(self):
pass
def fit(self,data,label='y'): ## 学习联合分布
# 还没实现异常处理
# if not isinstance(data, pd.DataFrame):
# print('please input DataFrame')
# return
# if not label in data.columns:
# print('please set name of label')
# return
y_tmp = data.groupby(label).count() # 聚合,得到每个类别的频数
self.prob_y = (y_tmp.iloc[:,0]).to_dict() ## 将dataframe转换为dict
self.prob_x = {} # 初始化特征的频数
# 对每一维特征xi
for xi in data.columns:
if xi!=label: # 排除y
xi_tmp = data.groupby([label,xi]).count() # 按照y和xi进行聚类求和,得到对应频数
val = xi_tmp.iloc[:,0].to_dict() ## 将dataframe转换为dict,该字典为该维的频数
self.prob_x[xi] = val # 将该字典加入到prob_x中
print(self.prob_x)
return
def predict(self,X): ## 预测
n,res = len(X.columns),[] # n为特征维数,res为返回结果
for x in X.values: # 对每个样本
y_prob, cls = 0,None # 初始化该样本对应的后验概率和输出类别
for c in self.prob_y.keys(): # 对每个类别,计算后验概率
prob = 1 # 初始化后验概率为1
for i in range(n): # 对每一维特征,开始连乘
prob *= self.prob_x[X.columns[i]][(c,x[i])]/self.prob_y[c] # 频数相除,得到频率,即条件概率P(X=xi|Y=c)
tmp = prob*self.prob_y[c]
if tmp>y_prob: # 取最值
y_prob = tmp
cls = c
res.append(cls)
return res
if __name__ == '__main__':
## 测试样例来自《统计学习方法》P63
trainSet = pd.DataFrame({'x1':[1,1,1,1,1,2,2,2,2,2,3,3,3,3,3],\
'x2':['S','M','M','S','S','S','M','M','L','L','L','M','M','L','L'],\
'y':[-1,-1,1,1,-1,-1,-1,1,1,1,1,1,1,1,-1]})
testSet = pd.DataFrame({'x1':[2],'x2':['S'],'y':[-1]})
mod = naiveBayes()
mod.fit(trainSet)
print('res: ', mod.predict(testSet.iloc[:,:-1]))
prob_x长这样:
结果:
*btw:这里,我采用的是dataframe避免了for循环,如果有更好的写法,请指教!