机器学习——朴素贝叶斯分类器

核心思想:

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

算法简介:

模型:

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

猜你喜欢

转载自blog.csdn.net/slx_share/article/details/80052048