为什么机器学习(四)—— 朴素贝叶斯的“训练”为什么这么轻松

续着上一篇说到的Iris数据集多分类问题,基于softmax的逻辑回归分类需要通过数据训练一轮轮地降低损失函数,以获得最佳的参数w和b。

而对于朴素贝叶斯算法来说,其核心源于贝叶斯公式,这个伟大的业余(?)数学家贝叶斯的著名公式:

P ( a ∣ b ) = P ( b ∣ a ) P ( a ) P ( b ) \begin{aligned} P(a|b) = \frac{P(b|a)P(a)}{P(b)} \end{aligned} P(ab)=P(b)P(ba)P(a)
其表现的是先验概率P(a)和后验概率P(a|b)之间的概率。

我们可以用一个形象的例子来说,比如相亲:在不知道其他情况下,我们知道一个普通小伙子被姑娘看上的概率是0.4。根据后续的交流,我们发现这个小伙子为人诚实,和蔼可亲,那么根据常识,被看上的概率应该提高了;如果这个小伙子收入年入百万,英俊潇洒,身高185…那么原来这个0.4的概率就会被不断地修正,不断地升高接近1.0。

我们刚刚这个例子中,一开始那个0.4的概率就是先验概率,后面不断地补充和小伙子相关的其他特征,不断修正得到的概率就是后验概率。

利用贝叶斯公式,我们可以定性的发现先验概率、后验概率与这些其他相关特征发生概率之间的关系。

回到朴素贝叶斯算法中,我们做多分类,也可以采用这种思想。一开始我们可以以这个类别在这个数据集中出现的比例为先验概率,在此之后,我们根据其他特征发生的概率、在这个实体是这个类别条件下发生此特征的概率来计算后验概率,之后比较后验概率(修正后的概率)的大小,选择后验概率最大的作为一个实例的预测值。

对于离散型特征,我们可以用每个特征出现的次数来作为概率:
P ( x i = v ∣ y = c ) = N x i = v , y = c N y = c \begin{aligned} P(x_i=v|y=c) = \frac{N_{x_i=v,y=c}}{N_{y=c}} \end{aligned} P(xi=vy=c)=Ny=cNxi=v,y=c
由于 P ( x ) P(x) P(x)可以认为是一个常数,所以最终我们需要比较
a r g m a x y P ( y = c ) ∏ i n P ( x i = v ∣ y = c ) \begin{aligned} argmax_y P(y=c)\prod_{i}^{n}P(x_i=v|y=c) \end{aligned} argmaxyP(y=c)inP(xi=vy=c)

这里 x i = v x_i=v xi=v代表第i个特征值为v,y=c代表为第c类

对于连续型特征,我们可以任务特征服从一维正态分布,用其概率密度函数来表示概率:
f ( x i = x ∣ y = c ) = 1 2 π σ e x p ( − ( x − μ ) 2 2 σ 2 ) \begin{aligned} f(x_i=x|y=c) = \frac{1}{\sqrt{2π}\sigma}exp(-\frac{(x-\mu)^2}{2\sigma^2}) \end{aligned} f(xi=xy=c)=2π σ1exp(2σ2(xμ)2)
同理最终我们要求:
a r g m a x y P ( y = c ) ∏ i n f ( x i ∣ y = c ) \begin{aligned} argmax_y P(y=c)\prod_{i}^{n}f(x_i|y=c) \end{aligned} argmaxyP(y=c)inf(xiy=c)

我们可以发现,朴素贝叶斯不需要数据一轮轮的训练来下降损失函数,只需要利用数据计算公式进行计算和比较即可。所以朴素贝叶斯比起softmax逻辑分类来说,“训练”是轻松很多了。(我要是softmax算法我可能要骂娘了hhh)

下面上代码:

import pandas as pd
from sklearn import datasets
import numpy as np

# 利用sklearn的datasets下载iris数据集
x_data = datasets.load_iris().data
y_data = datasets.load_iris().target

#打乱顺序,分为训练集测试集
np.random.seed(100)
np.random.shuffle(x_data)
np.random.seed(100)
np.random.shuffle(y_data)
dataset_size = len(x_data)
trainData_size = int(dataset_size*0.7)
testData_size = dataset_size - trainData_size
x_train = x_data[:trainData_size]
y_train = y_data[:trainData_size]
x_test = x_data[trainData_size:]
y_test = y_data[trainData_size:]


# 转为dataframe
train = pd.DataFrame(x_train,columns=['SpealLength', 'SpealWidth', 'PetalLength', 'PetalWidth'])
train.insert(0,'target',y_train)

# 训练过程(算公式过程)
# 开辟一个3*8的ndarray存3类4个特征的均值和标准差
w = np.zeros((3,8))
# 存储每类的数量
type_size = np.zeros(3)

# 分别对三类数据对应特征求均值和标准差
for type in range(3):
    temp = train[train['target']==type]
    type_size[type] = len(temp)
    temp = temp[['SpealLength', 'SpealWidth', 'PetalLength', 'PetalWidth']]
    mean = temp.mean()
    std = temp.std()
    for feature in range(4):
        w[type][feature * 2] = mean.iloc[feature]
        w[type][feature * 2 + 1] = std.iloc[feature]


# 求正态概率密度
def normal_f(mean,std,x):
    x = np.array(x)
    return 1/(np.sqrt(2*np.pi)*std)*np.exp(-np.square(x-mean)/(2*np.square(std)))

acc_num = 0
for i in range(len(x_test)):
    # 后验概率
    post_prob = np.zeros(3)
    for type in range(3):
        #先验概率赋值给后验概率
        post_prob[type] = type_size[type] / len(x_train)
        for feature in range(4):
            post_prob[type] *= normal_f(w[type][feature * 2],w[type][feature * 2 + 1],x_test[i][feature])
    ans = np.argmax(post_prob)
    print("guess:",ans,'\n',"right_ans:",y_test[i])
    if ans == y_test[i]:
        acc_num += 1
print("acc:",acc_num/len(x_test))

最终准确率100%
在这里插入图片描述

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值