朴素贝叶斯 Naive Bayes

Naive Bayes


特点


朴素贝叶斯是典型的生成学习方法

朴素贝叶斯的基本假设是条件独立性(强假设)
若条件之间存在概率依存关系,模型变为贝叶斯网络

基于上一条的假设,朴素贝叶斯方法高效,但分类性能受损

将输入的 x 分类到后验概率最大的类 y



原理

对于给定的输入 x
通过学习到的模型计算后验概率分布 P(Y = ck | X = x)
将后验概率最大的类作为x类的输出



朴素贝叶斯分类器 - 数学推导


先验概率分布

 P(Y = ck)   k = 1, 2, 3 … K

条件概率分布

 P(X = x | Y = ck) = P(X1 = x1, X2 = x2, … , Xn = xn | Y = ck)   k = 1, 2, 3 … K



后验概率最大化


朴素贝叶斯法将实例分类到后验概率最大化的类中

后验概率最大的,即期望风险最小化



贝叶斯参数估计


若使用极大似然估计法
对于某些数量为 0 的训练集数据类
极大似然估计法的分母是 0
不合理

贝叶斯参数估计在随机变量各个取值的频数上赋予正数ƛ
ƛ = 0 时就是极大似然估计
ƛ = 1 时,称为拉普拉斯平滑 Laplacian smoothing



步骤总结



Code

'''
----------------
朴素贝叶斯
----------------
数据集Mnist
训练集:60000
测试集:10000
类别:0/1/2/.../9手写体
每个实例为28x28的像素点,已展开为向量
----------------
运行时间:60.13s
准确率:0.84

train time 23s
test time 26s
----------------
'''

import numpy as np
import time

def loadData(fileName):
    '''
    加载数据
    :param filename: 文件路径
    :return: 数据集和标签集
    '''

    dataArr = []
    labelArr = []

    fr = open(fileName)

    for line in fr.readlines():
        curLine = line.strip().split(',')
        dataArr.append([int(int(num) > 128) for num in curLine[1:]])

        labelArr.append(int(curLine[0]))

    return dataArr, labelArr


def NaiveBayes(Py, Px_y, x):
    '''
    朴素贝叶斯进行概率估计
    :param Py: 先验概率分布
    :param Px_y: 条件概率分布
    :param x: 要估计的样本
    :return: 所有label的估计概率
    '''

    # 特征数目
    featureNum = 784
    # 类别数目
    classNum = 10
    # 建立存放所有标记估计概率的数组
    P = [0] * classNum

    # 对于每一个类别,单独估计其概率
    for i in range(classNum):

        # 对于 Py 和 Px_y 进行了log 处理,连乘变成了累加
        # 使用 sum 计算累加值
        sum = 0

        # 获取每一个条件概率值,进行累加
        for j in range(featureNum):
            # 第 i 个标签,第 j 个特征,x 样本的第 j 个特征的值(1/0)
            sum += Px_y[i][j][x[j]]

        # 和先验概率相加(log)
        P[i] = sum + Py[i]

    # 找最大值的索引
    return P.index(max(P))


def model_test(Py, Px_y, testDataArr, testLabelArr):
    '''
    测试测试集
    :param Py: 先验概率分布
    :param Px_y: 条件概率分布
    :param testDataArr: 测试数据集
    :param testLabelArr: 测试标签集
    :return: 准确率
    '''

    # 错误值计数
    errorCnt = 0

    # 循环遍历每一个样本
    for i in range(len(testDataArr)):
        # 获取预测值
        predict = NaiveBayes(Py, Px_y, testDataArr[i])

        # 与答案进行比较
        if predict != testLabelArr[i]:
            errorCnt += 1

    return 1 - (errorCnt / len(testDataArr))


def getAllProbability(trainDataArr, trainLabelArr):
    '''
    计算先验概率分布和条件概率分布
    :param trainDataArr: 训练集数据
    :param trainLabelArr: 训练集标签
    :return: 先验概率分布和条件概率分布
    '''

    # 数据集中手写图片像素为 28 * 28,转换为向量是 784
    featureNum = 784
    # 类别数目
    classNum = 10
    # 先验概率
    Py = np.zeros((classNum, 1))

    # 对每个类别进行一次循环,计算他们的先验概率分布
    for i in range(classNum):
        # 将标签转化成矩阵的形式
        # 里面的每一位与 i 比较,若相等,该位为 True,否则为 False
        # 计算共有多少个True,并加一(贝叶斯估计,lambda取1
        TrueNum = (np.sum(np.mat(trainLabelArr) == i)) + 1

        # 先验概率分布(Sj=10)
        Py[i] = TrueNum / (len(trainLabelArr) + 10)

    # 转换成对数形式
    # 先验概率分布可以转也可以不转
    # 条件概率分布由于乘项很多,结果可能会下溢出,故转成 log 形式
    Py = np.log(Py)

    # 计算条件概率分布
    Px_y = np.zeros((classNum, featureNum, 2))
    # 对标记进行遍历
    for i in range(len(trainLabelArr)):
        label = trainLabelArr[i]
        x = trainDataArr[i]
        for j in range(featureNum):
            # 在矩阵中对应位置加 1
            Px_y[label][j][x[j]] += 1


    # 循环每一个标记
    for label in range(classNum):
        # 循环每一个标记对应的每一个特征
        for j in range(featureNum):
            # 标记为label,第j个特征为0的个数
            Px_y0 = Px_y[label][j][0]
            # 标记为label,第j个特征为1的个数
            Px_y1 = Px_y[label][j][1]

            #  贝叶斯估计
            Px_y[label][j][0] = np.log((Px_y0 + 1) / (Px_y0 + Px_y1 + 2))
            Px_y[label][j][1] = np.log((Px_y1 + 1) / (Px_y0 + Px_y1 + 2))

    return Py, Px_y

if __name__ == "__main__":

    start = time.time()

    print("Start to read train set")
    trainDataArr, trainLabelArr = loadData("/Users/bigstone/Downloads/code/Statistical/Mnist/Mnist_train.csv")

    print("Start to read test set")
    testDataArr, testLabelArr = loadData("/Users/bigstone/Downloads/code/Statistical/Mnist/Mnist_test.csv")

    end1 = time.time()
    print("Time spend in reading data: ", end1 - start)
    start2 = time.time()

    # 学习先验概率分布和条件概率分布
    print("Start to train")
    Py, Px_y = getAllProbability(trainDataArr, trainLabelArr)

    end2 = time.time()
    print("Time spend in training model: ", end2 - start2)
    start3 = time.time()

    # 进行测试
    print("Start to test")
    accuracy = model_test(Py, Px_y, testDataArr, testLabelArr)

    end3 = time.time()
    print("Time spend in testing model: ", end3 - start3)

    # 输出准确率
    print("The accuracy is: ", accuracy)

    # 运行时间
    end = time.time()
    print("time spend: ", end - start)


你可能感兴趣的:(统计学习,机器学习,朴素贝叶斯算法,机器学习,人工智能,统计模型)