python实现朴素贝叶斯分类器(连续数据)

有用请点赞,没用请差评。

欢迎分享本文,转载请保留出处。

 

一、算法

算法原理参考周志华老师的《机器学习》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。

数据内容截图:

python实现朴素贝叶斯分类器(连续数据)_第1张图片 

 数据说明:

python实现朴素贝叶斯分类器(连续数据)_第2张图片

 源码:

# -*- 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%。

你可能感兴趣的:(机器学习,彭湃的专栏)