【机器学习】朴素贝叶斯(多分类版本)—— python3 实现方案

 根据《统计学习方法》第四章朴素贝叶斯算法流程写成,引入贝叶斯估计(平滑处理)

《机器学习实战》的朴素贝叶斯算法,是针对文本处理(垃圾邮件过滤)的算法,是二元分类(y=0或y=1),且特征的取值也是二元(x=0或x=1)的特殊算法,因此用numpy数组相加的方法,可以快速算出各特征取值的概率。但是推广的一般情况,即不同特征的取值范围各不相同时,无法把所有情况整合到一个数组中,故在实现时,使用字典来存储各种情况的概率,代价是空间和时间复杂度更大了,而且看上去不是那么简洁。应该还有更好的办法。  以下用简单的测试数据测试通过。

import numpy as np

class NB():
    '''
    朴素贝叶斯(Naive Bayes)
    '''
    def trainNB(self, dataSet, lamb=1):
        '''
        根据输入数据,训练NB模型
        :param dataSet: 训练集 m*(n+1),m是样本数,n是特征数, np.array
        :return: 各类别的信息字典 组成的列表
        '''
        labels = set(list(dataSet[:, -1]))  # 获取类别的取值
        m, n = dataSet.shape[0], dataSet.shape[1] - 1
        featureValues = []  # 所有特征所有可能的特征取值
        for featureindex in range(n):
            values = set(list(dataSet[:, featureindex]))
            featureValues.append(values)  # 元素为集合的列表,集合存储相应索引位特征的所有可能取值。

        NBlist = []  # 最终要返回的列表,即训练好的NB模型
        for label in labels:
            labeldict = {}  # 存储该类别的必要信息
            labeldict['label'] = label  # 类别标签信息
            labeldict['feature'] = {}  # 类别的特征信息, 因为特征有n个,这里还是用字典存储特征信息
            for i in range(n):
                labeldict['feature'][i] = {}  # 特征的值的信息,因为特征的取值个数>=2,这里还是用字典存储特征信息
                for value in featureValues[i]:
                    labeldict['feature'][i][value] = 0  # 初始化每个特征出现的次数为0
            numlabel = 0  # 记录该类别出现的次数
            for example in dataSet:
                if example[-1] == label:  # 找到属于该类别的样本
                    numlabel += 1
                    for i in range(n):
                        labeldict['feature'][i][example[i]] += 1  # 找到对应的特征值,使其出现次数+1
            labeldict['plabel'] = (numlabel + lamb) / (m + lamb * len(labels))  # 计算先验概率p,并做平滑处理
            for i in range(n):
                for value in featureValues[i]:
                    labeldict['feature'][i][value] = (labeldict['feature'][i][value] + lamb) / (numlabel + lamb * len(featureValues[i]))  # 根据该类别的总样本数,把出现次数转变成计算条件概率,并做平滑处理
            NBlist.append(labeldict)
        return NBlist

    def predict(self, NBlist, testData):
        '''
        输入待测数据,输出预测类别
        :param NBlist: 训练好的模型
        :param testData: shape=(n,)的待测数据,np.array
        :return: 预测结果
        '''
        prob = {}
        for nb in NBlist:
            p = np.log(nb['plabel'])  # 把连乘换成取对数相加,防止下溢(即太多小于1的数相乘,结果会变成0)
            for index, val in enumerate(testData):  # 计算每个类别的“可能性”
                p += np.log(nb['feature'][index][val])
            prob[nb['label']] = p
        return max(prob, key=lambda x: prob[x])  # 取键值最大的键



# 以下是测试数据
dataSet = np.array([[1, 5, -1],
           [1, 6, -1],
           [1, 6, 1],
           [1, 5, 1],
           [1, 5, -1],
           [2, 5, -1],
           [2, 6, -1],
           [2, 6, 1],
           [2, 7, 1],
           [2, 7, 1],
           [3, 7, 1],
           [3, 6, 1],
           [3, 6, 1],
           [3, 7, 1],
           [3, 7, -1]])
nb = NB()
NBlist = nb.trainNB(dataSet)
prob = nb.predict(NBlist, np.array([1, 7]))

猜你喜欢

转载自blog.csdn.net/zhenghaitian/article/details/81187247
今日推荐