《统计学习方法》——朴素贝叶斯法

  • 朴素贝叶斯法的学习与分类

朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法。对于给定的训练数据集,首先基于特征条件独立假设学习输入/输出的联合概率分布;然后基于此模型,对给定的输入x,利用贝叶斯定理求出后验概率最大的y。

基本方法

设输入空间X\subseteq R^{n}为n维向量的集合,输入空间为类标记集合Y=\left \{ c_{1},c_{2},...,c_{K} \right \}。输入为特征向量x\in X,输出为类标记y\in Y。X是定义在输入空间X上的随机变量,Y是定义在输出空间Y上的随机变量。P(X,Y)是X和Y的联合概率分布。训练数据集T=\left \{ (x_{1},y_{1}),(x_{2},y_{2}),...,(x_{N},y_{N}) \right \}由P(X,Y)独立同分布产生。

朴素贝叶斯法通过训练集学习联合概率分布P(X,Y)。具体地,学习以下先验概率分布及条件概率分布。

先验概率分布P(Y=c_{k}),\; \; \; k=1,2,...,K

条件概率分布P(X=x|Y=c_{k})=P(X^{(1)}=x^{(1)},...,X^{n}=x^{n}|Y=c_{k}),\; \; \; k=1,2,...,K

学习到联合概率分布P(X,Y),而条件概率分布有指数级数量的参数,其估计实际是不可行的。

朴素贝叶斯法对条件概率分布作了条件独立性的假设。由于这是一个较强的假设,朴素贝叶斯法也由此得名。具体地,条件独立性假设是

P(X=x|Y=c_{k})=P(X^{(1)}=x^{(1)},...,X^{(n)}=x^{(n)}|Y=c_{k})\\ =\prod_{j=1}^{n}P(X^{(j)}=x^{(j)}|Y=c_{k})

朴素贝叶斯法实际上学习到生成数据的机制,所以属于生成模型。条件独立假设等于是说用于分类的特征在类确定的条件下都是条件独立的。这一假设使朴素贝叶斯法变得简单,但有时会牺牲一定的分类准确率。

朴素贝叶斯法分类时,对给定的输入x,通过学习到的模型计算后验概率分布P(Y=c_{k}|X=x),将后验概率最大的类作为x的类输出。后验概率计算根据贝叶斯定理进行:

P(Y=c_{k}|X=x)=\frac{P(Y=c_{k})P(X=x|Y=c_{k})}{P(X=x)}\\ =\frac{P(Y=c_{k})\prod_{j}^{ }P(X^{(j)}=x^{(j)}|Y=c_{k})}{P(X=x)}

这是朴素贝叶斯法分类的基本公式。于是,朴素贝叶斯分类器可表示为:

y=f(x)=argmax_{c_{k}}\frac{P(Y=c_{k})\prod_{j}^{ }P(X^{(j)}=x^{(j)}|Y=c_{k})}{P(X=x)}

注意到,分母对所有c_{k}都是相同的,所以:

y=argmax_{c_{k}}P(Y=c_{k})\prod_{j}^{ }P(X^{(j)}=x^{(j)}|Y=c_{k})

  • 朴素贝叶斯法的参数估计

1.极大似然估计

在朴素贝叶斯法中,学习意味着估计P(Y=c_{k})P(X^{(j)}=x^{(j)}|Y=c_{k})。可以应用极大似然估计法估计相应的概率。

先验概率P(Y=c_{k})的极大似然估计是:

P(Y=c_{k})=\frac{\sum_{i=1}^{N}I(y_{i}=c_{k})}{N},\; \; \; k=1,2,...,K

设第j个特征x^{(j)}可能取值的集合为\left \{ a_{j1},a_{j2},...,a_{jS_{j}} \right \}条件概率P(X^{(j)}=a_{jl}|Y=c_{k})的极大似然估计是:

P(X^{(j)}=a_{jl}|Y=c_{k})=\frac{\sum_{i=1}^{N}I(x_{i}^{(j)}=a_{jl},y_{i}=c_{k})}{\sum_{i=1}^{N}I(y_{i}=c_{k})}j=1,2,...,N;\; l=1,2,...,S_{j};\; k=1,2,...,K

式中,x_{i}^{(j)}是第i个样本的第j个特征;a_{jl}是第j个特征可能取的第l个值;I为指示函数。

2.贝叶斯估计

用极大似然估计可能会出现所要估计的概率值为0的情况。这时会影响到后验概率的计算结果,使分类产生偏差。解决这一问题的方法是采用贝叶斯估计。

具体地,条件概率的贝叶斯估计是:

P_{\lambda }(X^{(j)}=a_{jl}|Y=c_{k})=\frac{\sum_{i=1}^{N}I(x_{i}^{(j)}=a_{jl},y_{i}=c_{k})+\lambda }{\sum_{i=1}^{N}I(y_{i}=c_{k})+S_{j}\lambda }

式中\lambda \geqslant 0,等价于在随机变量各个取值的频数上赋予一个正数\lambda > 0,当\lambda =0时就是极大似然估计。常取\lambda =1,这时称为拉普拉斯平滑。

同样,先验概率的贝叶斯估计是:

P_{\lambda }(Y=c_{k})=\frac{\sum_{i=1}^{N}I(y_{i}=c_{k})+\lambda }{N+K\lambda }

  • 练习

\lambda =0.2,试由下表的训练数据,利用先验概率的贝叶斯估计确定x=(2,S)^{T}的类标记y。表中X^{(1)},X^{(2)}为特征,取值的集合分别为A_{1}=\left \{ 1,2,3 \right \},A_{2}=\left \{ S,M,L \right \},Y为类标记,Y\in C=\left \{ 1,-1 \right \}

(1)自编程实现朴素贝叶斯算法,对上述表格中训练数据进行分类。

朴素贝叶斯算法:

输入:训练数据T=\left \{ (x_{1},y_{1}),(x_{2},y_{2}),...,(x_{N},y_{N}) \right \},其中x_{i}=(x_{i}^{(1)},x_{i}^{(2)},...,x_{i}^{(n)})^{T}x_{i}^{(j)}是第i个样本的第j个特征,x_{i}^{(j)}\in \left \{ a_{j1},a_{j2},...,a_{jS_{j}} \right \}a_{jl}是第j个特征可能取的第l个值,j=1,2,...,nl=1,2,...,S_{j}y_{i}\in \left \{ c_{1},c_{2},...,c_{K} \right \};实例x

输出:实例x的分类

应用极大似然估计的朴素贝叶斯法的算法步骤:

(1)计算先验概率及条件概率:

P(Y=c_{k})=\frac{\sum_{i=1}^{N}I(y_{i}=c_{k})}{N},\; \; \; k=1,2,...,K

P(X^{(j)}=a_{jl}|Y=c_{k})=\frac{\sum_{i=1}^{N}I(x_{i}^{(j)}=a_{jl},y_{i}=c_{k})}{\sum_{i=1}^{N}I(y_{i}=c_{k})}j=1,2,...,N;\; l=1,2,...,S_{j};\; k=1,2,...,K

(2)对于给定的实例x=(x^{(1)},x^{(2)},...,x^{(n)})^{T},计算:

P(Y=c_{k})=\prod_{j=1}^{n}P(X^{(j)}=x^{(j)}|Y=c_{k}),\; \; \; k=1,2,...,K

(3)确定实例x的类:

y=argmax_{c_{k}}P(Y=c_{k})\prod_{j=1}^{n}P(X^{(j)}=x^{(j)}|Y=c_{k})

代码如下:

# coding:utf-8
"""
@author:hanmy
@file:nb_mle.py
@time:2019/04/29
"""
class naiveBayes_MLE:
    def __init__(self, X, Y, N, n, K, x):
        self.X = X  # 训练数据的特征
        self.Y = Y  # 训练数据的类标记
        self.N = N  # 训练数据个数
        self.n = n  # 特征的个数
        self.K = K  # 类标记的个数
        self.x = x  # 待分类实例

    def prob(self):
        # 先验概率
        prior = {}
        # 条件概率
        conditional = {}
        for c in set(self.Y):
            prior[c] = 0
            conditional[c] = {}
            for j in range(self.n):
                for a in set(self.X[j]):
                    conditional[c][a] = 0

        # 计算先验概率和条件概率
        for i in range(self.N):
            prior[self.Y[i]] += 1
            for j in range(self.n):
                conditional[self.Y[i]][self.X[j][i]] += 1

        for c in set(self.Y):
            for j in range(self.n):
                for a in set(self.X[j]):
                    conditional[c][a] /= prior[c]

            prior[c] /= self.N

        return prior, conditional

    # 确定实例x的类
    def classifier(self):
        prior, conditional = self.prob()
        # 计算各类别的后验概率
        posterior = {}
        for c in set(self.Y):
            cond = 1
            for j in range(self.n):
                cond *= conditional[c][self.x[j]]
            posterior[c] = prior[c] * cond

        # 取最大后验概率的类别max(dict, key=dict.get)
        argmax = max(posterior, key=posterior.get)

        return posterior, argmax


if __name__ == "__main__":
    X = [[1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3],
         ['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]
    N = len(Y)
    n = len(X)
    K = len(set(Y))
    x = [2, 'S']

    nb = naiveBayes_MLE(X, Y, N, n, K, x)
    posterior, argmax = nb.classifier()
    print("每个类别的后验概率:", posterior)
    print("x=", x, "的类标记y为", argmax)

每个类别的后验概率: {1: 0.02222222222222222, -1: 0.06666666666666667}
x= [2, 'S'] 的类标记y为 -1

应用极大似然估计的朴素贝叶斯法的算法步骤:

(1)计算先验概率及条件概率:

P_{\lambda }(Y=c_{k})=\frac{\sum_{i=1}^{N}I(y_{i}=c_{k})+\lambda }{N+K\lambda },\; \; \; k=1,2,...,K

P_{\lambda }(X^{(j)}=a_{jl}|Y=c_{k})=\frac{\sum_{i=1}^{N}I(x_{i}^{(j)}=a_{jl},y_{i}=c_{k})+\lambda }{\sum_{i=1}^{N}I(y_{i}=c_{k})+S_{j}\lambda }j=1,2,...,N;\; l=1,2,...,S_{j};\; k=1,2,...,K

(2)对于给定的实例x=(x^{(1)},x^{(2)},...,x^{(n)})^{T},计算:

P(Y=c_{k})=\prod_{j=1}^{n}P(X^{(j)}=x^{(j)}|Y=c_{k}),\; \; \; k=1,2,...,K

(3)确定实例x的类:

y=argmax_{c_{k}}P(Y=c_{k})\prod_{j=1}^{n}P(X^{(j)}=x^{(j)}|Y=c_{k})

代码如下:

# coding:utf-8
"""
@author:hanmy
@file:nb_be.py
@time:2019/04/29
"""
class naiveBayes_BE:
    def __init__(self, X, Y, N, n, K, x, lamb):
        self.X = X  # 训练数据的特征
        self.Y = Y  # 训练数据的类标记
        self.N = N  # 训练数据个数
        self.n = n  # 特征的个数
        self.K = K  # 类标记的个数
        self.x = x  # 待分类实例
        self.lamb = lamb  # 贝叶斯估计的lambda

    def prob(self):
        # 先验概率
        prior = {}
        # 条件概率
        conditional = {}
        for c in set(self.Y):
            prior[c] = 0
            conditional[c] = {}
            for j in range(self.n):
                for a in set(self.X[j]):
                    conditional[c][a] = 0
        # 每个特征有多少个不同的特征值
        S = [0]*self.n
        for j in range(self.n):
            for _ in set(self.X[j]):
                S[j] += 1

        # 计算先验概率和条件概率
        for i in range(self.N):
            prior[self.Y[i]] += 1
            for j in range(self.n):
                conditional[self.Y[i]][self.X[j][i]] += 1

        for c in set(self.Y):
            for j in range(self.n):
                for a in set(self.X[j]):
                    conditional[c][a] = (conditional[c][a] + self.lamb) / (prior[c] + S[j]*self.lamb)

            prior[c] = (prior[c] + self.lamb) / (self.N + self.K*self.lamb)

        return prior, conditional

    # 确定实例x的类
    def classifier(self):
        prior, conditional = self.prob()
        # 计算各类别的后验概率
        posterior = {}
        for c in set(self.Y):
            cond = 1
            for j in range(self.n):
                cond *= conditional[c][self.x[j]]
            posterior[c] = prior[c] * cond

        # 取最大后验概率的类别max(dict, key=dict.get)
        argmax = max(posterior, key=posterior.get)

        return posterior, argmax


if __name__ == "__main__":
    X = [[1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3],
         ['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]
    N = len(Y)
    n = len(X)
    K = len(set(Y))
    x = [2, 'S']
    lamb = 0.2

    nb = naiveBayes_BE(X, Y, N, n, K, x, lamb)
    posterior, argmax = nb.classifier()
    print("每个类别的后验概率:", posterior)
    print("x=", x, "的类标记y为", argmax)

每个类别的后验概率: {1: 0.024891774891774892, -1: 0.06506624688442872}
x= [2, 'S'] 的类标记y为 -1

(2)试分别调用sklearn.naive_bayes的GaussianNB、BernoulliNB、MultinomialNB模块,对上述表格中训练数据进行分类。

GaussianNB(高斯分布):连续分量

ComplementNB(改进的多项分布):用于不平衡数据集

BernoulliNB(伯努利分布):X_{i}只能取(0,1)

MultinomialNB(多项分布):离散变量

MultinomialNB(alpha=1.0, fit_prior=True, class_prior=None)

  • MultinomialNB的方法

1.fit:对数据集进行训练

2.predict:对测试点进行分类

3.predict_proba:对测试点属于不同分类的概率

4.score:输入测试集,评价训练效果

5.partial_fit:数据分块学习

# coding:utf-8
"""
@author:hanmy
@file:nb_sklearn.py
@time:2019/04/30
"""
import numpy as np
from sklearn.naive_bayes import GaussianNB, BernoulliNB, MultinomialNB
from sklearn import preprocessing  # 预处理


if __name__ == "__main__":
    X_train = np.array([
        [1, "S"],
        [1, "M"],
        [1, "M"],
        [1, "S"],
        [1, "S"],
        [2, "S"],
        [2, "M"],
        [2, "M"],
        [2, "L"],
        [2, "L"],
        [3, "L"],
        [3, "M"],
        [3, "M"],
        [3, "L"],
        [3, "L"]
    ])

    y_train = np.array([-1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1])
    enc = preprocessing.OneHotEncoder(categories='auto')  # 将训练数据变成one-hot编码
    enc.fit(X_train) 
    X_train = enc.transform(X_train).toarray()  # 转换为数组
    print(X_train)
    clf = MultinomialNB(alpha=0.0000001)  # lambda
    clf.fit(X_train, y_train)  # 训练
    X_new = np.array([[2, "S"]])
    X_new = enc.transform(X_new).toarray()
    y_predict = clf.predict(X_new)  # 分类
    print("{}被分类为:{}".format(X_new, y_predict))
    print(clf.predict_proba(X_new))  # 概率

结果如下:

[[1. 0. 0. 0. 0. 1.]
 [1. 0. 0. 0. 1. 0.]
 [1. 0. 0. 0. 1. 0.]
 [1. 0. 0. 0. 0. 1.]
 [1. 0. 0. 0. 0. 1.]
 [0. 1. 0. 0. 0. 1.]
 [0. 1. 0. 0. 1. 0.]
 [0. 1. 0. 0. 1. 0.]
 [0. 1. 0. 1. 0. 0.]
 [0. 1. 0. 1. 0. 0.]
 [0. 0. 1. 1. 0. 0.]
 [0. 0. 1. 0. 1. 0.]
 [0. 0. 1. 0. 1. 0.]
 [0. 0. 1. 1. 0. 0.]
 [0. 0. 1. 1. 0. 0.]]
[[0. 1. 0. 0. 0. 1.]]被分类为:[-1]
[[0.74999998 0.25000002]]

分类1和分类-1的概率比值大致为1:3,与应用极大似然估计的朴素贝叶斯法的结果一致。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值