技术人生,  机器学习

朴素贝叶斯法的极大似然估计/贝叶斯估计

朴素贝叶斯法是一种生成模型,通过学习训练数据集的联合概率分布利用条件概率公式和贝叶斯定理,计算数据属于每一类的概率即后验概率并取最大值所在类作为分类结果,这一过程同样等价于期望风险最小化。特别的,朴素贝叶斯对条件概率分布作了条件独立性的假设,使其得以更为简单广泛的应用。

算法具体实现流程如下:

1.计算先验概率和条件概率;

2.计算每一类的后验概率;

3.取后验概率最大的类作为实例的类。

代码实现方面首先需要引入特征与类标记的取值集合作为计算的条件之一,接着导入训练数据和对应的标签,最后导入测试实例。

x_ranges = [[1,2,3],['S','M','L']]              #特征取值集合
y_ranges = [1,-1]                               #类标记取值集合

train_data = [[1,'S',-1],                       #训练数据集
             [1,'M',-1],
             [1,'M',1],
             [1,'S',1],
             [1,'S',-1],
             [2,'S',-1],
             [2,'M',-1],
             [2,'M',1],
             [2,'L',1],
             [2,'L',1],
             [3,'L',1],
             [3,'M',1],
             [3,'M',1],
             [3,'L',1],
             [3,'L',-1]]

x_train = [[i[0],i[1]] for i in train_data]     #训练数据
y_train = [i[-1] for i in train_data]           #标签数据

t = [2,'S']                                     #目标测试数据

下面分别用极大似然估计和贝叶斯估计两种方法实现朴素贝叶斯算法。

首先是极大似然估计。

计算先验概率,即每类标签占总标签的比例。

def maximum_likelihood_estimation():            #极大似然估计
    priori_probability = {}                     #先验概率
    for yi in y_ranges:
        count = 0
        for i in train_data:
            if i[-1] == yi:
                count += 1
        priori_probability[yi] = count / len(x_train)

计算条件概率,即在标签确定的情况下,特定特征取某个特征值的概率。

    conditional_probability = {}                #条件概率,使用三个下标分别代表第几个特征,特征值,标签值
    for x in range(len(x_ranges)):
        conditional_probability[x]={}
        for xi in x_ranges[x]:
            conditional_probability[x][xi] = {}
            for yi in y_ranges:
                count = 0
                count_all = 0
                for i in train_data:
                    if i[-1] == yi:
                        count_all += 1
                        if i[x] == xi:
                            count += 1
                conditional_probability[x][xi][yi] = count / count_all

计算后验概率,由于后验概率的分母由全概率公式得到,都是一致的,所以用于比较可以省略分母,仅保留分子部分,后验概率即测试实例属于某个类标签的概率。

    class_probability = {}                      #计算后验概率
    for yi in y_ranges:
        class_probability[yi] = priori_probability[yi]
        for x in range(len(x_ranges)):
            class_probability[yi] *= conditional_probability[x][t[x]][yi]

取后验概率最大值所在的类作为实例的分类结果。

    result_data = list(class_probability.items())  #排序找到最大值,对应的类标签即为分类结果
    result_data.sort(key=lambda x: x[1], reverse=True)
    result = result_data[0][0]
    print('极大似然估计结果:',result)

面部分使用贝叶斯估计实现朴素贝叶斯算法。

算法实现的各个部分基本都是一致的,只是计算先验概率和条件概率时采用贝叶斯估计的想法,避免0值的出现影响计算结果,因此引入一个正数值加在分子上,分母加上该值对应的乘积。 当该值取1时,称为拉普拉斯平滑。

def bayesian_estimation():                      #贝叶斯估计
    n = 1                                       #调节参数η

    priori_probability = {}
    for yi in y_ranges:
        count = 0
        for i in train_data:
            if i[-1] == yi:
                count += 1
        priori_probability[yi] = (count + n) / (len(x_train) + len(y_ranges) * n)

    conditional_probability = {}
    for x in range(len(x_ranges)):
        conditional_probability[x]={}
        for xi in x_ranges[x]:
            conditional_probability[x][xi] = {}
            for yi in y_ranges:
                count = 0
                count_all = 0
                for i in train_data:
                    if i[-1] == yi:
                        count_all += 1
                        if i[x] == xi:
                            count += 1
                conditional_probability[x][xi][yi] = (count + n) / (count_all + len(x_ranges[x]) * n)

    class_probability = {}
    for yi in y_ranges:
        class_probability[yi] = priori_probability[yi]
        for x in range(len(x_ranges)):
            class_probability[yi] *= conditional_probability[x][t[x]][yi]

    result_data = list(class_probability.items())
    result_data.sort(key=lambda x: x[1], reverse=True)
    result = result_data[0][0]
    print('贝叶斯估计结果:',result)

运行这两个函数。

maximum_likelihood_estimation()
bayesian_estimation()

运行结果如下:

基于上述算法可以进一步简化代码。由于实际结果的得出只依赖于和目标数据的各个特征值相关的条件概率值,因此可以省去全部的条件概率的计算而只计算必要的几个概率值即可。

简化的代码中还优化了复杂的计数方法,使用len()函数进行计数;特征取值集合也不必额外给出,而直接基于训练数据集计算得到;不再单独提取训练数据和标签数据,由于更新了计数方法,实际计算中直接使用原数据集显得更加清晰明确。

新的代码如下。

train_data = [[1,'S',-1],                       #训练数据集
             [1,'M',-1],
             [1,'M',1],
             [1,'S',1],
             [1,'S',-1],
             [2,'S',-1],
             [2,'M',-1],
             [2,'M',1],
             [2,'L',1],
             [2,'L',1],
             [3,'L',1],
             [3,'M',1],
             [3,'M',1],
             [3,'L',1],
             [3,'L',-1]]

x_ranges = [set([i[j] for i in train_data]) for j in range(len(train_data[0]) - 1)]   #特征取值集合
y_ranges = set([i[-1] for i in train_data])                 #类标记取值集合

t = [2,'S']                                     #目标测试数据

def maximum_likelihood_estimation():
    priori_probability = {}                     #先验概率
    for yi in y_ranges:
        priori_probability[yi] = len([i for i in train_data if i[-1] == yi]) / len(train_data)

    conditional_probability = {}                #条件概率,只计算目标数据所需的条件概率,两个下标分别为目标的第几个特征和标签值
    for xi in range(len(t)):
        conditional_probability[xi] = {}
        for yi in y_ranges:
            conditional_probability[xi][yi] = len([i for i in train_data if i[xi] == t[xi] and i[-1] == yi]) / len([i for i in train_data if i[-1] == yi])

    class_probability = {}                      #后验概率
    for yi in y_ranges:
        class_probability[yi] = priori_probability[yi]
        for xi in range(len(t)):
            class_probability[yi] *= conditional_probability[xi][yi]

    result_data = list(class_probability.items())  #排序找到最大值,对应的类标签即为分类结果
    result_data.sort(key=lambda x: x[1], reverse=True)
    result = result_data[0][0]
    print('极大似然估计结果:',result)

def bayesian_estimation():                      #贝叶斯估计
    n = 1                                       #调节参数η

    priori_probability = {}                     #先验概率
    for yi in y_ranges:
        priori_probability[yi] = (len([i for i in train_data if i[-1] == yi]) + n) / (len(train_data) + len(y_ranges) * n)

    conditional_probability = {}                #条件概率,只计算目标数据所需的条件概率,两个下标分别为目标的第几个特征和标签值
    for xi in range(len(t)):
        conditional_probability[xi] = {}
        for yi in y_ranges:
            conditional_probability[xi][yi] = (len([i for i in train_data if i[xi] == t[xi] and i[-1] == yi]) + n) / (len([i for i in train_data if i[-1] == yi]) + len(x_ranges[xi]) * n)

    class_probability = {}                      #后验概率
    for yi in y_ranges:
        class_probability[yi] = priori_probability[yi]
        for xi in range(len(t)):
            class_probability[yi] *= conditional_probability[xi][yi]
    
    result_data = list(class_probability.items())  #排序找到最大值,对应的类标签即为分类结果
    result_data.sort(key=lambda x: x[1], reverse=True)
    result = result_data[0][0]
    print('贝叶斯估计结果:',result)

maximum_likelihood_estimation()
bayesian_estimation()

A WindRunner. VoyagingOne

留言

您的电子邮箱地址不会被公开。 必填项已用*标注