朴素贝叶斯算法简单高效,在处理分类问题上,是应该首先考虑的方法之一。
通过本教程,你将学到朴素贝叶斯算法的原理和python版本的逐步实现。
更新:查看后续的关于朴素贝叶斯使用技巧的文章“better naive bayes: 12 tips to get the most from the naive bayes algorithm”
朴素贝叶斯分类器,matt buck保留部分版权
关于朴素贝叶斯
朴素贝叶斯算法是一个直观的方法,使用每个属性归属于某个类的概率来做预测。你可以使用这种监督性学习方法,对一个预测性建模问题进行概率建模。
给定一个类,朴素贝叶斯假设每个属性归属于此类的概率独立于其余所有属性,从而简化了概率的计算。这种强假定产生了一个快速、有效的方法。
给定一个属性值,其属于某个类的概率叫做条件概率。对于一个给定的类值,将每个属性的条件概率相乘,便得到一个数据样本属于某个类的概率。
我们可以通过计算样本归属于每个类的概率,然后选择具有最高概率的类来做预测。
通常,我们使用分类数据来描述朴素贝叶斯,因为这样容易通过比率来描述、计算。一个符合我们目的、比较有用的算法需要支持数值属性,同时假设每一个数值属性服从正态分布(分布在一个钟形曲线上),这又是一个强假设,但是依然能够给出一个健壮的结果。
预测糖尿病的发生
本文使用的测试问题是“皮马印第安人糖尿病问题”。
这个问题包括768个对于皮马印第安患者的医疗观测细节,记录所描述的瞬时测量取自诸如患者的年纪,怀孕和血液检查的次数。所有患者都是21岁以上(含21岁)的女性,所有属性都是数值型,而且属性的单位各不相同。
每一个记录归属于一个类,这个类指明以测量时间为止,患者是否是在5年之内感染的糖尿病。如果是,则为1,否则为0。
机器学习文献中已经多次研究了这个标准数据集,好的预测精度为70%-76%。
下面是pima-indians.data.csv文件中的一个样本,了解一下我们将要使用的数据。
注意:下载文件,然后以.csv扩展名保存(如:pima-indians-diabetes.data.csv)。查看文件中所有属性的描述。
6,148,72,35,0,33.6,0.627,50,11,85,66,29,0,26.6,0.351,31,08,183,64,0,0,23.3,0.672,32,11,89,66,23,94,28.1,0.167,21,00,137,40,35,168,43.1,2.288,33,1
朴素贝叶斯算法教程
教程分为如下几步:
1.处理数据:从csv文件中载入数据,然后划分为训练集和测试集。
2.提取数据特征:提取训练数据集的属性特征,以便我们计算概率并做出预测。
3.单一预测:使用数据集的特征生成单个预测。
4.多重预测:基于给定测试数据集和一个已提取特征的训练数据集生成预测。
5.评估精度:评估对于测试数据集的预测精度作为预测正确率。
6.合并代码:使用所有代码呈现一个完整的、独立的朴素贝叶斯算法的实现。
1.处理数据
首先加载数据文件。csv格式的数据没有标题行和任何引号。我们可以使用csv模块中的open函数打开文件,使用reader函数读取行数据。
我们也需要将以字符串类型加载进来属性转换为我们可以使用的数字。下面是用来加载匹马印第安人数据集(pima indians dataset)的loadcsv()函数。
import csvdef loadcsv(filename): lines = csv.reader(open(filename, rb)) dataset = list(lines) for i in range(len(dataset)): dataset[i] = [float(x) for x in dataset[i]] return dataset
我们可以通过加载皮马印第安人数据集,然后打印出数据样本的个数,以此测试这个函数。
filename = 'pima-indians-diabetes.data.csv'dataset = loadcsv(filename)print('loaded data file {0} with {1} rows').format(filename, len(dataset))
运行测试,你会看到如下结果:
loaded data file iris.data.csv with 150 rows
下一步,我们将数据分为用于朴素贝叶斯预测的训练数据集,以及用来评估模型精度的测试数据集。我们需要将数据集随机分为包含67%的训练集合和包含33%的测试集(这是在此数据集上测试算法的通常比率)。
下面是splitdataset()函数,它以给定的划分比例将数据集进行划分。
import randomdef splitdataset(dataset, splitratio): trainsize = int(len(dataset) * splitratio) trainset = [] copy = list(dataset) while len(trainset) bestprob: bestprob = probability bestlabel = classvalue return bestlabel
测试predict()函数如下:
summaries = {'a':[(1, 0.5)], 'b':[(20, 5.0)]}inputvector = [1.1, '?']result = predict(summaries, inputvector)print('prediction: {0}').format(result)
运行测试,你会得到如下结果:
prediction: a
多重预测
最后,通过对测试数据集中每个数据样本的预测,我们可以评估模型精度。getpredictions()函数可以实现这个功能,并返回每个测试样本的预测列表。
def getpredictions(summaries, testset): predictions = [] for i in range(len(testset)): result = predict(summaries, testset[i]) predictions.append(result) return predictions
测试getpredictions()函数如下。
summaries = {'a':[(1, 0.5)], 'b':[(20, 5.0)]}testset = [[1.1, '?'], [19.1, '?']]predictions = getpredictions(summaries, testset)print('predictions: {0}').format(predictions)
运行测试,你会看到如下结果:
predictions: ['a', 'b']
计算精度
预测值和测试数据集中的类别值进行比较,可以计算得到一个介于0%~100%精确率作为分类的精确度。getaccuracy()函数可以计算出这个精确率。
def getaccuracy(testset, predictions): correct = 0 for x in range(len(testset)): if testset[x][-1] == predictions[x]: correct += 1 return (correct/float(len(testset))) * 100.0
我们可以使用如下简单的代码来测试getaccuracy()函数。
testset = [[1,1,1,'a'], [2,2,2,'a'], [3,3,3,'b']]predictions = ['a', 'a', 'a']accuracy = getaccuracy(testset, predictions)print('accuracy: {0}').format(accuracy)
运行测试,你会得到如下结果:
accuracy: 66.6666666667
合并代码
最后,我们需要将代码连贯起来。
下面是朴素贝叶斯python版的逐步实现的全部代码。
# example of naive bayes implemented from scratch in pythonimport csvimport randomimport math def loadcsv(filename): lines = csv.reader(open(filename, rb)) dataset = list(lines) for i in range(len(dataset)): dataset[i] = [float(x) for x in dataset[i]] return dataset def splitdataset(dataset, splitratio): trainsize = int(len(dataset) * splitratio) trainset = [] copy = list(dataset) while len(trainset) bestprob: bestprob = probability bestlabel = classvalue return bestlabel def getpredictions(summaries, testset): predictions = [] for i in range(len(testset)): result = predict(summaries, testset[i]) predictions.append(result) return predictions def getaccuracy(testset, predictions): correct = 0 for i in range(len(testset)): if testset[i][-1] == predictions[i]: correct += 1 return (correct/float(len(testset))) * 100.0 def main(): filename = 'pima-indians-diabetes.data.csv' splitratio = 0.67 dataset = loadcsv(filename) trainingset, testset = splitdataset(dataset, splitratio) print('split {0} rows into train={1} and test={2} rows').format(len(dataset), len(trainingset), len(testset)) # prepare model summaries = summarizebyclass(trainingset) # test model predictions = getpredictions(summaries, testset) accuracy = getaccuracy(testset, predictions) print('accuracy: {0}%').format(accuracy) main()
运行示例,得到如下输出:
split 768 rows into train=514 and test=254 rowsaccuracy: 76.3779527559%