五、(1)朴素贝叶斯
朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法 [1] 。最为广泛的两种分类模型是决策树模型(Decision Tree Model)和朴素贝叶斯模型(Naive Bayesian Model,NBM)。
和决策树模型相比,朴素贝叶斯分类器(Naive Bayes Classifier,或 NBC)发源于古典数学理论,有着坚实的数学基础,以及稳定的分类效率。同时,NBC模型所需估计的参数很少,对缺失数据不太敏感,算法也比较简单。理论上,NBC模型与其他分类方法相比具有最小的误差率。但是实际上并非总是如此,这是因为NBC模型假设属性之间相互独立,这个假设在实际应用中往往是不成立的,这给NBC模型的正确分类带来了一定影响。
本文利用一组糖尿病数据集来演示朴素贝叶斯算法的流程,参考链接为http://python.jobbole.com/81019。数据集下载地址:https://blog.youkuaiyun.com/weixin_43718084/article/details/90377478
下载完改文件名为csv即可。
完整代码如下:
# -*- coding: utf-8 -*-
"""
Created on Sun May 19 22:59:05 2019
@author: sun
"""
#处理数据,导入csv数据集,从载入时的字符串格式到数值
import csv
import math
def loadCsv(filename):
lines = csv.reader(open(filename, "r"))
dataset = list(lines)
print(dataset)
for i in range(len(dataset)):
dataset[i] = [float(x) for x in dataset[i]]
return dataset
filename = '糖尿病数据.csv'
dataset = loadCsv(filename)
print(('载入糖尿病数据 {0} 一共 {1} 行').format(filename, len(dataset)))
#接下来是 splitDataset() 函数,它将会按比例拆分一个给定的数据集。
import random
def splitDataset(dataset, splitRatio):
trainSize = int(len(dataset) * splitRatio)
trainSet = []
copy = list(dataset)
while len(trainSet) < trainSize:
index = random.randrange(len(copy))
trainSet.append(copy.pop(index))
return [trainSet, copy]
#我们可以通过定义一个玩具数据来测试这个函数,来拆分数据集为训练集和测试集,并且打印出来。
dataset = [[1], [2], [3], [4],[5]]
#划分训练集大小
splitRatio = 0.75
train, test = splitDataset(dataset, splitRatio)
print(('Split {0} rows into 训练集 with {1} and 测试集 with {2}').format(len(dataset), train, test))
#这个函数假设最后一个属性保存的是类别值。这个函数返回了一个词典,分别是类别和类别下的一系列数据。
def separateByClass(dataset):
separated = {}
for i in range(len(dataset)):
vector = dataset[i]
if (vector[-1] not in separated):
separated[vector[-1]] = []
separated[vector[-1]].append(vector)
return separated
#设置数据测试,末尾的0和1代表类别
dataset = [[6,148,0], [2,21,0], [3,22,1]]
separated = separateByClass(dataset)
print(('分类类别: {0}').format(separated))
#计算每一个类别下的每一个属性的平均值,平均值是数据的中心或者中心的趋势,然后我们在计算概率的时候,将会用它作为我们高斯分布的平均值
def mean(numbers):
return sum(numbers)/float(len(numbers))
#计算每一个类别下所有属性的标准偏差。这个标准方差描述了数据变化的趋势,并且我们在计算概率时,将会用它作为高斯分布的标准差
#注意是标准偏差不是标准差
def stdev(numbers):
avg = mean(numbers)
variance = sum([pow(x-avg,2) for x in numbers])/float(len(numbers)-1)
return math.sqrt(variance)
#测试数字1,2,3,4,5
numbers = [1,2,3,4,5]
print(('Summary of {0}: 平均值={1}, 标准偏差={2}').format(numbers, mean(numbers), stdev(numbers)))
#汇总数据集。对于给定的一列数据实例,我们可以计算每一个属性的平均值和标准差。
#zip 函数将每一个属性的平均值和标准差组合起来了
def summarize(dataset):
summaries = [(mean(attribute), stdev(attribute)) for attribute in zip(*dataset)]
del summaries[-1]
return summaries
#测试数据来测试这个摘要函数,它表明第一个属性和第二个属性的平均值和标准偏差有非常显著的不同。
dataset = [[1,20,0], [2,21,1], [3,22,0]]
summary = summarize(dataset)
print(('属性摘要测试结果: {0}').format(summary))
#先将同一个类别的数据放在一起。然后计算每一个属性的摘要。
def summarizeByClass(dataset):
separated = separateByClass(dataset)
summaries = {}
for classValue, instances in separated.items():
summaries[classValue] = summarize(instances)
return summaries
#测试数据来测试这个摘要函数
dataset = [[1,20,1], [2,21,0], [3,22,1], [4,22,0]]
summary = summarizeByClass(dataset)
print(('两个类别的属性测试结果: {0}').format(summary))
#计算机高斯概率密度函数
def calculateProbability(x, mean, stdev):
exponent = math.exp(-(math.pow(x-mean,2)/(2*math.pow(stdev,2))))
return (1 / (math.sqrt(2*math.pi) * stdev)) * exponent
#用样本数据来测试这个公式
x = 71.5
mean = 73
stdev = 6.2
probability = calculateProbability(x, mean, stdev)
print(('属于这一类的概率: {0}').format(probability))
'''
#计算类别的概率
#现在我们可以计算某一个属性的值属于每一个类别的概率了,我们可以结合所有的属性值的概率,最后得到整个数据属于每一个类别的概率。
我们通过连乘把所有的概率结合在一起,在下面的 calculateClassProbabilities() 中,给定数据的概率通过连乘所有的属性概率得到,
结果是一个词典包含了属性值和对应的概率
'''
def calculateClassProbabilities(summaries, inputVector):
probabilities = {}
for classValue, classSummaries in summaries.items():
probabilities[classValue] = 1
for i in range(len(classSummaries)):
mean, stdev = classSummaries[i]
x = inputVector[i]
probabilities[classValue] *= calculateProbability(x, mean, stdev)
return probabilities
#测试一下 calculateClassProbabilities() 函数
summaries = {0:[(1, 0.5)], 1:[(20, 5.0)]}
inputVector = [1.1, '?']
probabilities = calculateClassProbabilities(summaries, inputVector)
print(('属于每个类的概率: {0}').format(probabilities))
#计算一个数据实例属于每一个类别的概率了,我们可以寻找最大的概率,然后返回对应的类别
def predict(summaries, inputVector):
probabilities = calculateClassProbabilities(summaries, inputVector)
bestLabel, bestProb = None, -1
for classValue, probability in probabilities.items():
if bestLabel is None or probability > 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(('预测属于类别: {0}').format(result))
#批量预测,预测多个
#预估模型的准确率,通过预测每一个测试数据集。这 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, '?'],[2,1,'?']]
predictions = getPredictions(summaries, testSet)
print(('预测属于类别: {0}').format(predictions))
#预测值可以和测试集中的类别值对比,然后准确率可以被算出来。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'],[4,4,4,'c']]
predictions = ['a', 'a', 'a','a']
accuracy = getAccuracy(testSet, predictions)
print(('准确度为: {0}%').format(accuracy))
运行结果如下:
搞定收工。
“☺☺☺ 若本篇文章对你有一丝丝帮助,请帮顶、评论点赞,谢谢。☺☺☺”
↓↓↓↓