分类——朴素贝叶斯分类器以及Python实现

核心思想

根据训练数据获取模型的后验概率,对应后验概率最大的类即预测类。

算法简介

模型

  1. 先验概率: p ( y = C k ) p(y=C_{k}) p(y=Ck)
  2. 条件概率: p ( X = x ∣ y = C k ) p(X=x|y=C_{k}) p(X=xy=Ck)
  3. 后验概率: p ( y = C k ∣ X = x ) p(y=C_{k}|X=x) p(y=CkX=x)
    朴素的含义:输入向量x的各个维度间是相互独立的,那么条件概率的计算公式可以大大简化 p ( X = x ∣ y = C k ) = ∏ j n p ( X j = x j ∣ y = C k ) p(X=x|y=C_{k})=\prod_j^{n}p(X^{j}=x^{j}|y=C_{k}) p(X=xy=Ck)=jnp(Xj=xjy=Ck)其中n为输入维度数。
    根据贝叶斯定理:
    p ( y = C k ∣ X = x ) = p ( X = x ∣ y = C k ) p ( y = C k ) p ( X = x ) p(y=C_{k}|X=x)=\frac{p(X=x|y=C_{k})p(y=C_{k})}{p(X=x)} p(y=CkX=x)=p(X=x)p(X=xy=Ck)p(y=Ck) 由于 p ( X = x ) {p(X=x)} p(X=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])))

我的GitHub
注:如有不当之处,请指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值