有用请点赞,没用请差评。
欢迎分享本文,转载请保留出处。
一、算法
算法原理参考周志华老师的《机器学习》p151和李航老师的《统计学习方法》。
博客内容部分借鉴于腾讯云“海天一树”老师。
二、数据集
本文中的数据集使用的是“皮马印第安人糖尿病数据集”。该数据集由美国国立糖尿病、消化和肾脏疾病研究所(United States National Institute of Diabetes and Digestive and Kidney Diseases,简称NIDDK)提供。这里的“皮马”指的是位于美国亚利桑那州南部的一个县。
该数据集可从 https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv 下载,具体方法是打开此链接后,会看到数据展现在网页中,右击save as,保存类型选为“Microsoft Excel Comman Separated Values File“,即CSV格式,文件名按默认为pima-indians-diabetes.data.csv。
数据内容截图:
数据说明:
源码:
# -*- coding:utf-8 -*-
# naive Bayes 朴素贝叶斯法(连续数据)
"""
算法参考周志华老师的《机器学习》
实现了对连续数据的贝叶斯分类器
使用数据为“皮马印第安人糖尿病数据集”。该数据集由美国国立糖尿病、消化和肾脏疾病研究所(United States National Institute of Diabetes and Digestive and Kidney Diseases,简称NIDDK)提供。
"""
import math
import csv
import random
class Bayes(object):
def __init__(self,trainData):
self.trainData=trainData
# self.inputVector=inputVector
# model_par以字典形式存放每一个类别的方差
self.model_para={}
def tarin_bayesModel(self):
# 将训练集按照类别进行提取
separated_class=self.separateByClass()
# vectors是列表,包含的是每个类别对应的向量集
for classValue, vectors in separated_class.items():
# 将每一个类别的均值和方差保存在对应的键值对中
self.model_para[classValue] = self.summarize(vectors)
return self.model_para
# 计算均值
def mean(self,numbers):
return sum(numbers) / float(len(numbers))
# 计算方差,注意是分母是n-1
def stdev(self,numbers):
avg = self.mean(numbers)
variance = sum([pow(x - avg, 2) for x in numbers]) / float(len(numbers) - 1)
return math.sqrt(variance)
# 对每一类样本的每个特征计算均值和方差,结果保存在列表中,依次为第一维特征、第二维特征等...的均值和方差
def summarize(self,vectors):
# zip利用 * 号操作符,可以将不同元组或者列表压缩为为列表集合。用来提取每类样本下的每一维的特征集合
summaries = [(self.mean(attribute), self.stdev(attribute)) for attribute in zip(*vectors)]
# 将代表类别的最后一个数据删掉,只保留均值和方差
del summaries[-1]
return summaries
# 将训练集按照类别进行提取,以字典形式存放,Key为类别,value为列表,列表中包含的是每个类别对应的向量集
def separateByClass(self):
#字典用于存放分类后的向量集合
separated_class = {}
for i in range(len(self.trainData)):
vector = self.trainData[i]
# vector[-1]为每组数据的类别
if (vector[-1] not in separated_class):
separated_class[vector[-1]] = []
# 将每列数据存放在对应的类别下,列表形式
separated_class[vector[-1]].append(vector)
return separated_class
# 假定服从正态分布,对连续属性计算概率密度函数,公式参考周志华老师的西瓜书P151
def calProbabilityDensity(self,x, mean, stdev):
# x为待分类数据
exponent = math.exp(-(math.pow(x-mean,2)/(2*math.pow(stdev,2))))
return (1 / (math.sqrt(2*math.pi) * stdev)) * exponent
# 计算待分类数据的联合概率
def calClassProbabilities(self, inputVector):
# summaries为训练好的贝叶斯模型参数, inputVector为待分类数据(单个)
# probabilities用来保存待分类数据对每种类别的联合概率
probabilities = {}
# classValue为字典的key(类别) ,classSummaries为字典的vlaue(每个类别每维特征的均值和方差),列表形式
for classValue, classSummaries in self.model_para.items():
probabilities[classValue] = 1
# len(classSummaries)表示有多少特征维度
for i in range(len(classSummaries)):
# mean, stdev分贝别表示每维特征对应的均值和方差
mean, stdev = classSummaries[i]
# 提取待分类数据的i维数据值
x = inputVector[i]
# 计算联合概率密度
probabilities[classValue] *= self.calProbabilityDensity(x, mean, stdev)
# 返回概率最大的类别
prediction=max(probabilities,key=probabilities.get)
return prediction
# 准备数据
def loadCsv(filename):
lines = csv.reader(open(filename, "r"))
dataset = list(lines)
for i in range(len(dataset)):
dataset[i] = [float(x) for x in dataset[i]]
return dataset
# 将原始数据集划分为训练集和测试集,splitRatio为划分比例。
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]
# 计算分类准确率
def calAccuracy(testData,bayes):
correct_nums=0
for i in range(len(testData)):
# 逐次计算每一个数据的分类类别
if testData[i][-1]== bayes.calClassProbabilities(testData[i]):
correct_nums += 1
return correct_nums
def main():
filename = 'D:\\python3_anaconda3\\学习\机器学习\\机器学习数据集\\糖尿病数据集\\pima-indians-diabetes.data.csv'
# 训练集和测试集的划分比例
splitRatio = 0.67
dataset = loadCsv(filename)
trainData, testData = splitDataset(dataset, splitRatio)
bayes=Bayes(trainData)
# model为训练之后的bayes分类器模型的概率参数
model=bayes.tarin_bayesModel()
# print(model)
correct_nums=calAccuracy(testData, bayes)
print("分类准确率 %f%%"%(correct_nums/len(testData) * 100.0))
if __name__=="__main__":
main()
因为划分训练集和测试集是随机划分,因此每次运行的结果可能不一样,平均维持在74%。