Python实现机器学习算法:朴素贝叶斯算法
'''
数据集:Mnist
训练集数量:60000
测试集数量:10000
'''
import numpy as np
import time
def loadData(fileName):
'''
加载文件
:param fileName:要加载的文件路径
:return: 数据集和标签集
'''
# 存放数据及标记
dataArr = [];
labelArr = []
# 读取文件
fr = open(fileName)
# 遍历文件中的每一行
for line in fr.readlines():
# 获取当前行,并按“,”切割成字段放入列表中
# strip:去掉每行字符串首尾指定的字符(默认空格或换行符)
# split:按照指定的字符将字符串切割成每个字段,返回列表形式
curLine = line.strip().split(',')
# 将每行中除标记外的数据放入数据集中(curLine[0]为标记信息)
# 在放入的同时将原先字符串形式的数据转换为整型
# 此外将数据进行了二值化处理,大于128的转换成1,小于的转换成0,方便后续计算
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: 要估计的样本x
:return: 返回所有label的估计概率
'''
# 设置特征数目
featrueNum = 784
# 设置类别数目
classNum = 10
# 建立存放所有标记的估计概率数组
P = [0] * classNum
# 对于每一个类别,单独估计其概率
for i in range(classNum):
# 初始化sum为0,sum为求和项。
# 在训练过程中对概率进行了log处理,所以这里原先应当是连乘所有概率,最后比较哪个概率最大
# 但是当使用log处理时,连乘变成了累加,所以使用sum
sum = 0
# 获取每一个条件概率值,进行累加
for j in range(featrueNum):
sum += Px_y[i][j][x[j]]
# 最后再和先验概率相加(也就是式4.7中的先验概率乘以后头那些东西,乘法因为log全变成了加法)
P[i] = sum + Py[i]
# max(P):找到概率最大值
# P.index(max(P)):找到该概率最大值对应的所有(索引值和标签值相等)
return P.index(max(P))
def accuracy(Py, Px_y, testDataArr, testLabelArr):
'''
对测试集进行测试
:param Py: 先验概率分布
:param Px_y: 条件概率分布
:param testDataArr: 测试集数据
:param testLabelArr: 测试集标记
:return: 准确率
'''
# 错误值计数
errorCnt = 0
# 循环遍历测试集中的每一个样本
for i in range(len(testDataArr)):
# 获取预测值
presict = NaiveBayes(Py, Px_y, testDataArr[i])
# 与答案进行比较
if presict != testLabelArr[i]:
# 若错误 错误值计数加1
errorCnt += 1
# 返回准确率
return 1 - (errorCnt / len(testDataArr))
def getAllProbability(trainDataArr, trainLabelArr):
'''
通过训练集计算先验概率分布和条件概率分布
:param trainDataArr: 训练数据集
:param trainLabelArr: 训练标记集
:return: 先验概率分布和条件概率分布
'''
# 设置样本特诊数目,数据集中手写图片为28*28,转换为向量是784维。
# (我们的数据集已经从图像转换成784维的形式了,CSV格式内就是)
featureNum = 784
# 设置类别数目,0-9共十个类别
classNum = 10
# 初始化先验概率分布存放数组,后续计算得到的P(Y = 0)放在Py[0]中,以此类推
# 数据长度为10行1列
# 各个类别的先验概率分布
Py = np.zeros((classNum, 1))
# 对每个类别进行一次循环,分别计算它们的先验概率分布
# 计算公式为书中"4.2节 朴素贝叶斯法的参数估计 公式4.8"
for i in range(classNum):
# 下方式子拆开分析
# np.mat(trainLabelArr) == i:将标签转换为矩阵形式,里面的每一位与i比较,若相等,该位变为Ture,反之False
# np.sum(np.mat(trainLabelArr) == i):计算上一步得到的矩阵中Ture的个数,进行求和(直观上就是找所有label中有多少个
# 为i的标记,求得4.8式P(Y = Ck)中的分子)
# np.sum(np.mat(trainLabelArr) == i)) + 1:参考“4.2.3节 贝叶斯估计”,例如若数据集总不存在y=1的标记,也就是说
# 手写数据集中没有1这张图,那么如果不加1,由于没有y=1,所以分子就会变成0,那么在最后求后验概率时这一项就变成了0,再
# 和条件概率乘,结果同样为0,不允许存在这种情况,所以分子加1,分母加上K(K为标签可取的值数量,这里有10个数,取值为10)
# 参考公式4.11
# (len(trainLabelArr) + 10):标签集的总长度+10.
# ((np.sum(np.mat(trainLabelArr) == i)) + 1) / (len(trainLabelArr) + 10):最后求得的先验概率
Py[i] = ((np.sum(np.mat(trainLabelArr) == i)) + 1) / (len(trainLabelArr) + 10)
# 转换为log对数形式
# log书中没有写到,但是实际中需要考虑到,原因是这样:
# 最后求后验概率估计的时候,形式是各项的相乘(“4.1 朴素贝叶斯法的学习” 式4.7),这里存在两个问题:1.某一项为0时,结果为0.
# 这个问题通过分子和分母加上一个相应的数可以排除,前面已经做好了处理。2.如果特征特别多(例如在这里,需要连乘的项目有784个特征
# 加一个先验概率分布一共795项相乘,所有数都是0-1之间,结果一定是一个很小的接近0的数。)理论上可以通过结果的大小值判断, 但在
# 程序运行中很可能会向下溢出无法比较,因为值太小了。所以人为把值进行log处理。log在定义域内是一个递增函数,也就是说log(x)中,
# x越大,log也就越大,单调性和原数据保持一致。所以加上log对结果没有影响。此外连乘项通过log以后,可以变成各项累加,简化了计算。
# 在似然函数中通常会使用log的方式进行处理(至于此书中为什么没涉及,我也不知道)
Py = np.log(Py)
# 计算条件概率 Px_y=P(X=x|Y = y)
# 计算条件概率分成了两个步骤,下方第一个大for循环用于累加,参考书中“4.2.3 贝叶斯估计 式4.10”,下方第一个大for循环内部是
# 用于计算式4.10的分子,至于分子的+1以及分母的计算在下方第二个大For内
# 初始化为全0矩阵,用于存放所有情况下的条件概率
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,计算式4.10的分母,以及分子和分母之间的除法
# 循环每一个标记(共10个)
for label in range(classNum):
# 循环每一个标记对应的每一个特征
for j in range(featureNum):
# 获取y=label,第j个特诊为0的个数
Px_y0 = Px_y[label][j][0]
# 获取y=label,第j个特诊为1的个数
Px_y1 = Px_y[label][j][1]
# 对式4.10的分子和分母进行相除,再除之前依据贝叶斯估计,分母需要加上2(为每个特征可取值个数)
# 分别计算对于y= label,x第j个特征为0和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 read transSet')
trainDataArr, trainLabelArr = loadData('../Mnist/mnist_train.csv')
# 获取测试集
print('start read testSet')
testDataArr, testLabelArr = loadData('../Mnist/mnist_test.csv')
# 开始训练,学习先验概率分布和条件概率分布
print('start to train')
Py, Px_y = getAllProbability(trainDataArr, trainLabelArr)
# 使用习得的先验概率分布和条件概率分布对测试集进行测试
print('start to test')
accuracy = accuracy(Py, Px_y, testDataArr, testLabelArr)
# 打印准确率
print('the accuracy is:', accuracy)
# 打印时间
print('time span:', time.time() - start)
start read transSet
start read testSet
start to train
start to test
the accuracy is: 0.8432999999999999
time span: 90.73810172080994
Python实现机器学习算法:朴素贝叶斯算法的更多相关文章
- Python机器学习算法 — 朴素贝叶斯算法(Naive Bayes)
朴素贝叶斯算法 -- 简介 朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法.最为广泛的两种分类模型是决策树模型(Decision Tree Model)和朴素贝叶斯模型(Naive Baye ...
- 机器学习:python中如何使用朴素贝叶斯算法
这里再重复一下标题为什么是"使用"而不是"实现": 首先,专业人士提供的算法比我们自己写的算法无论是效率还是正确率上都要高. 其次,对于数学不好的人来说,为了实 ...
- 吴裕雄--天生自然python机器学习:朴素贝叶斯算法
分类器有时会产生错误结果,这时可以要求分类器给出一个最优的类别猜测结果,同 时给出这个猜测的概率估计值. 概率论是许多机器学习算法的基础 在计算 特征值取某个值的概率时涉及了一些概率知识,在那里我们先 ...
- 【十大算法实现之naive bayes】朴素贝叶斯算法之文本分类算法的理解与实现
关于bayes的基础知识,请参考: 基于朴素贝叶斯分类器的文本聚类算法 (上) http://www.cnblogs.com/phinecos/archive/2008/10/21/1315948.h ...
- Python机器学习笔记:朴素贝叶斯算法
朴素贝叶斯是经典的机器学习算法之一,也是为数不多的基于概率论的分类算法.对于大多数的分类算法,在所有的机器学习分类算法中,朴素贝叶斯和其他绝大多数的分类算法都不同.比如决策树,KNN,逻辑回归,支持向 ...
- 机器学习---用python实现朴素贝叶斯算法(Machine Learning Naive Bayes Algorithm Application)
在<机器学习---朴素贝叶斯分类器(Machine Learning Naive Bayes Classifier)>一文中,我们介绍了朴素贝叶斯分类器的原理.现在,让我们来实践一下. 在 ...
- 朴素贝叶斯算法的python实现
朴素贝叶斯 算法优缺点 优点:在数据较少的情况下依然有效,可以处理多类别问题 缺点:对输入数据的准备方式敏感 适用数据类型:标称型数据 算法思想: 朴素贝叶斯比如我们想判断一个邮件是不是垃圾邮件,那么 ...
- 朴素贝叶斯算法--python实现
朴素贝叶斯算法要理解一下基础: [朴素:特征条件独立 贝叶斯:基于贝叶斯定理] 1朴素贝叶斯的概念[联合概率分布.先验概率.条件概率**.全概率公式][条件独立性假设.] 极大似然估计 ...
- 朴素贝叶斯算法原理及Spark MLlib实例(Scala/Java/Python)
朴素贝叶斯 算法介绍: 朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法. 朴素贝叶斯的思想基础是这样的:对于给出的待分类项,求解在此项出现的条件下各个类别出现的概率,在没有其它可用信息下,我 ...
- 朴素贝叶斯算法的python实现方法
朴素贝叶斯算法的python实现方法 本文实例讲述了朴素贝叶斯算法的python实现方法.分享给大家供大家参考.具体实现方法如下: 朴素贝叶斯算法优缺点 优点:在数据较少的情况下依然有效,可以处理多类 ...
随机推荐
- oracle查询每隔5分钟区间内的数据量
SELECT COUNT (DISTINCT tmp.PLATE) totalNum, tmp.newTime FROM ( SELECT T .LICENSE_PLATE plate, TO_CHA ...
- [NOIP2005普及组]采药(01背包)
题目描述 描述 辰辰是个很有潜能.天资聪颖的孩子,他的梦想是称为世界上最伟大的医师.为此,他想拜附近最有威望的医师为师.医师为了判断他的资质,给他出了一个难题.医师把他带到个到处都是草药的山洞里对他说 ...
- Python学习记录之----网络通信(二)
网络通信 socket 这一节太难了,还是看TA的吧 http://www.cnblogs.com/alex3714/articles/5830365.html 不能执行top等类似的 会持续输出 ...
- 转:[你必须知道的异步编程]——异步编程模型(APM)
本专题概要: 引言 你知道APM吗? 你想知道如何使用异步编程模型编写代码吗? 使用委托也可以实现异步编程,你知道否? 小结 一.引言 在前面的C#基础知识系列中介绍了从C#1.0——C#4.0中一些 ...
- 【JavaScript 6连载】三、构造函数
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- 13年总结js,css,java xml
--------------------------------------javaScript知识点----------------------------- jQuery对象[Object obj ...
- 5、CentOS 6.5系统安装配置Nginx-1.2.7+PHP-5.3.22环境
一,操作系统 以最小服务器形式安装系统,并添加开发工具库,便于后期编译使用. 此处基本都是下一步,下一步,不再废话. 安装完成,进入系统,调通网络,关闭防火墙或打开相应的WEB端口. 以下安装操作默认 ...
- ES6知识整理(4)--数组的扩展
最近工作比较忙,基本每天都会加班到很晚.处理一些客户端兼容问题以及提升用户体验的优化.也将近一周没更文了,现在继续es6的学习总结. 上篇回顾 ES6知识整理(三)--函数的扩展 扩展运算符 形式是3 ...
- 4~20mA
4~20mA电流输出芯片XTR111完整电路 0-5v转0-20ma和0-5v转4-20ma 压控恒流源电路 4-20mA电流环路发送器入门
- eclipse的svn插件添加代理访问svn
1.首先找到插件配置文件 C:\Users\Administrator\AppData\Roaming\Subversion这个目录下的servers文件 打开找到 # http-proxy-host ...