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)
|