当前位置:   article > 正文

机器学习实验-贝叶斯分类器_贝叶斯分类器实验 花

贝叶斯分类器实验 花

山东大学软件学院机器学习基础课程实验报告

一、前期准备

鸢尾花数据集

iris以鸢尾花的特征作为数据来源,常用在分类操作中。该数据集由3种不同类型的鸢尾花的各50个样本数据构成。其中的一个种类与另外两个种类是线性可分离的,后两个种类是非线性可分离的。

该数据集包含了4个属性:

& Sepal.Length(花萼长度),单位是cm;

& Sepal.Width(花萼宽度),单位是cm;

& Petal.Length(花瓣长度),单位是cm;

& Petal.Width(花瓣宽度),单位是cm;

种类:Iris Setosa(山鸢尾)、Iris Versicolour(杂色鸢尾),以及Iris Virginica(维吉尼亚鸢尾)

数据集可以从网上下载

需要手动分割训练集和数据集。我将五分之四的数据集作为训练集对贝叶斯分类器进行训练,将剩余数据集作为测试集,采用训练好的贝叶斯分类器模型对其进行预测。训练集与测试集的数据是随机选取的。

贝叶斯分类器

下面只是写一个目录,只把用到的朴素贝叶斯分类器的核心思想记录了一下,其它详见西瓜书。

贝叶斯准则
基于最小错误率的贝叶斯决策
极大似然估计
朴素贝叶斯分类器

简化:“属性条件独立性假设”

分类过程:

  1. 估计类先验概率
    • 拉普拉斯修正 “平滑”
  2. 估计类条件概率
    • 离散属性:拉普拉斯修正 “平滑”
    • 连续属性:高斯函数
  3. 估计后验概率
    • 后验概率 = 类先验概率*所有的类条件概率
    • 后验概率最大的即为所属类别
    • 常通过取对数的方式将“连乘”转化为“连加”,以避免数值下溢
半朴素贝叶斯分类器

二、实验过程

1.分割数据集

数据集是从网上下载的.csv文件,直接放在了项目里。

首先以4 : 1(训练集:测试集)的比例分割数据集:

因为每个类别都有50条数据,我初始是按照每个类别随机取10条数据作为测试集的想法做的,代码如下:

def split_dataset(data: pd.DataFrame):
    """
    分割训练集和测试集
    :param data: iris dataset
    :return: trainSet, testSet
    """
    # 随机采样 每个品种各取1/5作为测试集
    test_index = random.sample(range(50), 10)
    test_index.extend(random.sample(range(50, 100), 10))
    test_index.extend(random.sample(range(100, 150), 10))
    print("测试集包括:")
    print(test_index)
    testSet = data.iloc[test_index]
    train_index = list(range(150))
    for index in test_index:
        train_index.remove(index)
    trainSet = data.iloc[train_index]
    return trainSet, testSet
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

后来考虑了一下,为了使随机采样更具随机性,我选择了直接随机取样。把随机采样改为:

test_index = random.sample(range(150), 30)
  • 1

2.计算类先验概率

	# 类先验概率
    # 拉普拉斯修正
    num = train.shape[0]
    prior_0 = np.log((train.loc[train.Species == Species[0]].shape[0]+1)/(num+3))
    prior_1 = np.log((train.loc[train.Species == Species[1]].shape[0]+1)/(num+3))
    prior_2 = np.log((train.loc[train.Species == Species[2]].shape[0]+1)/(num+3))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这里,采用了拉普拉斯修正,进行“平滑”处理。

同时,为了避免数值下溢,对数值进行取对数处理。

使用train.loc[train.Species == Species[0]]获得训练集中品种为"setosa"的数据,使用.shape[0]取得行数。

3.计算所有列的类条件概率

首先,因为鸢尾花数据集都是连续数据,所以要用高斯函数计算类条件概率,函数代码如下:

def continuous_attr_p(value, mean, var):
    """

    :param value: xi
    :param mean: 均值
    :param var: 方差
    :return: 类条件概率p
    """
    p = 1 / ((2 * PI * var) ** 0.5) * math.exp(-(value - mean)**2 / (2 * var))
    # print("p:")
    # print(p)
    return p
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

计算所有类条件概率的思路:根据物种类型,取出训练集中同属于一类的数据。对于这些数据中的每一列,计算它们的均值和方差,代入测试集数据x该列的值,计算类条件概率,判断这些数据属于哪个物种类型,将每列的类条件概率存放在定义好的字典中。属于"setosa"就存放在storage0中,以此类推。为了避免数值下溢,对数值进行取对数处理。

Species = ["setosa", "versicolor", "virginica"]
  • 1

定义字典的代码:

storage0 = {"Sepal.Length": 0, "Sepal.Width": 0, "Petal.Length": 0, "Petal.Width": 0}
storage1 = {"Sepal.Length": 0, "Sepal.Width": 0, "Petal.Length": 0, "Petal.Width": 0}
storage2 = {"Sepal.Length": 0, "Sepal.Width": 0, "Petal.Length": 0, "Petal.Width": 0}
  • 1
  • 2
  • 3

该思路实现的代码为:

for spes in Species:
    train_dic = train.loc[train.Species == spes]
    for column in train_dic.columns:
        if column != 'Species':  # 去除预测标签的影响
            mean = np.mean(train_dic[column])
            var = np.var(train_dic[column])
            p = np.log(continuous_attr_p(x[column], mean, var))
            if spes == Species[0]:
                storage0[column] = p
            elif spes == Species[1]:
                storage1[column] = p
            elif spes == Species[2]:
                storage2[column] = p
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

4.计算后验概率

定义一个后验概率数组,存放三个品种的后验概率。

post_p = np.zeros(3, np.float64)
post_p[0] = prior_0
post_p[1] = prior_1
post_p[2] = prior_2
  • 1
  • 2
  • 3
  • 4

因为先验概率和所有的类条件概率都取了对数,所以后验概率=类先验概率+所有的类条件概率之和

for column in train.columns:
    if column != 'Species':
        post_p[0] = post_p[0] + storage0[column]
        post_p[1] = post_p[1] + storage1[column]
        post_p[2] = post_p[2] + storage2[column]
  • 1
  • 2
  • 3
  • 4
  • 5

返回三者中的最大值的索引,索引与Species数组相对应,得到的即为该测试数据所属的类别:

post_p_i = np.argmax(post_p, axis=0)
print("post_p_i", post_p_i)
return post_p_i
  • 1
  • 2
  • 3

主函数

贝叶斯分类器的实现
	Data = pd.read_csv('iris.csv')
    # 划分数据集
    train_set, test_set = split_dataset(Data)

    # 存放分类器对测试集的分类结果
    classify_result = []
    for index, row in test_set.iterrows():
        classify_result.append(Species[classifier(row, train_set)])
    # 将分类结果添加到测试集中
    test_set.insert(test_set.shape[1], 'forecast', classify_result)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
可视化方式

使用seaborn绘图工具

①以Speciesx轴,使用sns.countplot()绘制条形图,显示训练集中各物种的个数:

colors = sns.color_palette('pastel')
sns.countplot(x="Species", palette='pastel', data=train_set)
plt.show()
  • 1
  • 2
  • 3

②统计测试集中分类正确和分类错误的数目:

# 分类正确的数目
df1 = test_set[['Species']]
df2 = test_set[['forecast']]
df = pd.concat([df1, df2], axis=1)
df['result'] = np.where(df['Species'] == df['forecast'], 'true', 'false')
colors = sns.color_palette('pastel')
sns.countplot(x="result", palette='pastel', data=df)
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

③以Sepal.Lengthx轴,以Petal.Lengthy轴绘制回归图,对比以Species列为分类标准和以forecast列为分类标准的图像的差异。

sns.lmplot(x='Sepal.Length', y='Petal.Length', hue='Species',
           data=test_set, markers=['*', 'o', '+'])
plt.show()

sns.lmplot(x='Sepal.Length', y='Petal.Length', hue='forecast',
           data=test_set, markers=['*', 'o', '+'])
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
评估方式

采用准确率分类正确的样本数/总样本数进行评估

TP = 0
for index, row in comparison.iterrows():
    if row["Species"] == row['forecast']:
        TP += 1

Accuracy = TP / 30
print('正确率: {:.2%}'.format(Accuracy))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

三、输出截屏

注:下列输出结果为使用jupyter运行后得到的结果。

1.测试集选取

随机选取的测试集标号:
请添加图片描述

2.训练集各物种个数

可视化显示训练集中各物种的个数:
请添加图片描述

3.各测试数据计算出的后验概率与种类选取

输出后验概率:post_p[0]为setosa物种的后验概率,post_p[1]为versicolor物种的后验概率,post_p[2]为virginica物种的后验概率。取三者的最大值作post_p_i,即预测的类别,0为setosa物种,1为versicolor物种,2为virginica物种。

下图仅为部分数据:
请添加图片描述

4.测试集正确分类与贝叶斯分类结果对比

①统计测试集中分类正确和分类错误的数目:
请添加图片描述

应该得到的正确分类:
请添加图片描述
实际上得到的结果:
请添加图片描述

5.正确率

请添加图片描述

四、全部代码

import numpy as np
import random
import math
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

# from torcheval.metrics import functional as TMF

PI = math.pi
Species = ["setosa", "versicolor", "virginica"]


def split_dataset(data: pd.DataFrame):
    """
    分割训练集和测试集
    :param data: iris dataset
    :return: trainSet, testSet
    """
    # 随机采样
    test_index = random.sample(range(150), 30)
    print("测试集包括:")
    print(test_index)
    testSet = data.iloc[test_index]
    train_index = list(range(150))
    for index in test_index:
        train_index.remove(index)
    trainSet = data.iloc[train_index]
    return trainSet, testSet


def continuous_attr_p(value, mean, var):
    """

    :param value: xi
    :param mean: 均值
    :param var: 方差
    :return: 类条件概率p
    """
    p = 1 / ((2 * PI * var) ** 0.5) * math.exp(-(value - mean) ** 2 / (2 * var))
    # print("p:")
    # print(p)
    return p


storage0 = {"Sepal.Length": 0, "Sepal.Width": 0, "Petal.Length": 0, "Petal.Width": 0}
storage1 = {"Sepal.Length": 0, "Sepal.Width": 0, "Petal.Length": 0, "Petal.Width": 0}
storage2 = {"Sepal.Length": 0, "Sepal.Width": 0, "Petal.Length": 0, "Petal.Width": 0}


def classifier(x, train: pd.DataFrame):
    """
     朴素贝叶斯分类
     鸢尾花数据集都是连续数据
    :param x: 测试集的一条数据
    :param train: 训练集模型
    :return: 预测结果
    """
    # 类先验概率
    # 拉普拉斯修正
    num = train.shape[0]
    prior_0 = np.log((train.loc[train.Species == Species[0]].shape[0] + 1) / (num + 3))
    prior_1 = np.log((train.loc[train.Species == Species[1]].shape[0] + 1) / (num + 3))
    prior_2 = np.log((train.loc[train.Species == Species[2]].shape[0] + 1) / (num + 3))

    # 计算所有列的类条件概率
    for spes in Species:
        train_dic = train.loc[train.Species == spes]
        for column in train_dic.columns:
            if column != 'Species':  # 去除预测标签的影响
                mean = np.mean(train_dic[column])
                var = np.var(train_dic[column])
                p = np.log(continuous_attr_p(x[column], mean, var))
                if spes == Species[0]:
                    storage0[column] = p
                elif spes == Species[1]:
                    storage1[column] = p
                elif spes == Species[2]:
                    storage2[column] = p

    post_p = np.zeros(3, np.float64)
    post_p[0] = prior_0
    post_p[1] = prior_1
    post_p[2] = prior_2
    for column in train.columns:
        if column != 'Species':
            post_p[0] = post_p[0] + storage0[column]
            post_p[1] = post_p[1] + storage1[column]
            post_p[2] = post_p[2] + storage2[column]

    print("post_p[0]", post_p[0])
    print("post_p[1]", post_p[1])
    print("post_p[2]", post_p[2])
    post_p_i = np.argmax(post_p, axis=0)
    print("post_p_i", post_p_i)
    return post_p_i


if __name__ == '__main__':

    Data = pd.read_csv('iris.csv')
    # 划分数据集
    train_set, test_set = split_dataset(Data)

    # 显示训练集物种分布情况
    #     a=[]
    #     for index, row in train_set.iterrows():
    #         if row["Species"] == Species[0]:
    #             a.append(1)
    #         elif  row["Species"] == Species[1]:
    #             a.append(2)
    #         else:
    #             a.append(3)
    #     train_set.insert(train_set.shape[1], 'digit',a)
    colors = sns.color_palette('pastel')
    sns.countplot(x="Species", palette='pastel', data=train_set)
    plt.show()

    # 存放分类器对测试集的分类结果
    classify_result = []
    for index, row in test_set.iterrows():
        classify_result.append(Species[classifier(row, train_set)])

    # 将分类结果添加到测试集中
    test_set.insert(test_set.shape[1], 'forecast', classify_result)

    sns.lmplot(x='Sepal.Length', y='Petal.Length', hue='Species',
               data=test_set, markers=['*', 'o', '+'])
    plt.show()

    sns.lmplot(x='Sepal.Length', y='Petal.Length', hue='forecast',
               data=test_set, markers=['*', 'o', '+'])
    plt.show()

    # 分类正确的数目
    df1 = test_set[['Species']]
    df2 = test_set[['forecast']]
    df = pd.concat([df1, df2], axis=1)
    df['result'] = np.where(df['Species'] == df['forecast'], 'true', 'false')
    colors = sns.color_palette('pastel')
    sns.countplot(x="result", palette='pastel', data=df)
    plt.show()

    TP = 0
    for index, row in test_set.iterrows():
        if row["Species"] == row['forecast']:
            TP += 1

    Accuracy = TP / 30

    print('正确率: {:.2%}'.format(Accuracy))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151

五、心得体会

​ 通过本次实验,我对贝叶斯分类器有了更深刻的了解,清楚了朴素贝叶斯分类的基本流程,加深了对机器学习基本方法的理解与应用,提高了自身的代码技能和分析并解决问题的能力,为之后的实验和学习奠定了基础,受益匪浅。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/在线问答5/article/detail/875582
推荐阅读
相关标签
  

闽ICP备14008679号