(代码在最下面)

正在学习人工智能课程,作业要求自己写一个贝叶斯分类器,分享一下,一起学习

 

题目描述:

对于Wine数据库,用Python实现以下内容:

1)利用非参数密度估计方法估计先验概率密度。

2)建立最小错误率Bayes分类器。

3)检验分类器性能。

实验内容及数学原理:

(1)利用非参数密度估计方法估计先验概率密度。

设样本类型为Y,样本有Ck种类别,k=1,2,3

非参数密度估计先验概率为:

P(Y=Ck)=N(yi=ck)/N,k=1,2,3

∴先验概率P(Y=Ck)=样本中Ck的数目/样本总数,k=1,2,3

∴P(Y='1')=N1/N总

  P(Y='2')=N2/N总

P(Y='3')=N3/N总

 

(2)建立最小错误率Bayes分类器。

已知输入变量X={x1,x2,x3,…,x13}

∵xi∈{x1,x2,…,x13}为独立同分布概率

∴联合概率密度P(x1,x2,…,x13)=P(x1)P(x2)…P(x13)

又已知先验概率P(Y=Ck)  k=1,2,3

∴后验概率为P(Y=Ck|X)=P(X|Y=Ck)P(Y=Ck)/∑P(X|Y=Ck)P(Y=Ck)

即P(Y=Ck|X)=P(i=1,2…,13)P(xi|Y=Ck)* P(Y=Ck)/∑P(X|Y=Ck)P(Y=Ck)

又假设xi的分布服从一维正态分布

∴需要根据样本数据估计十三个特征的正态分布的参数μ,sˆ2

μi=`xi  i=1,2,3…,13

sˆ2= E(x-μ)ˆ2

得到条件概率密度函数P(Xi|Y=Ck),k=1,2,3

∵P(xi)是P(X)的边缘密度概率分布

正态分布的联合概率分布仍为正态分布

∴从而得到后验概率

P(Y=Ck|X)=P P(xi|Y=Ck)*P(Y=Ck)/ P(X)      ,k=1,2,3

又因为分母都相同,所以只需判断分子P(i=1,2…,13)P(xi|Y=Ck)* P(Y=Ck)

∴通过判别一个输入X的

MAX=max{

PP(xi|Y=C1)* P(Y=C1),

PP(xi|Y=C2)* P(Y=C2),

PP(xi|Y=C3)* P(Y=C3)  }

 

若 MAX=PP(xi|Y=C1)*P(Y=C1),则X为C1类

若 MAX=PP(xi|Y=C2)*P(Y=C2),则X为C2类

若 MAX=PP(xi|Y=C3)*P(Y=C3),则X为C3类

 

(3)检验分类器性能。

采用0-1损失函数,对数据集进行K折交叉验证,划分为K个不相交的子集,每次选取K-1个子集进行训练,其余1个子集进行验证,得到测试准确率Rtest。重复K次,计算Rtest的均值,即为正确率。

 

python代码实现(有注释说明):

# Load libraries
import pandas
import numpy as np
import scipy.stats as stats
import matplotlib.pyplot as plt
from sklearn import model_selection  # 模型比较和选择包
from sklearn.naive_bayes import GaussianNB


class Bayes_Test():

    # 读取样本 数据集
    def load_dataset(self):
        url = 'wine.data'
        names = ['class', 'Al', 'Ma', 'Ash', 'Aoa', 'Mag', 'Top', 'Fl', 'No',
                 'Pr', 'Co', 'Hue', 'OD', 'Pro']
        dataset = pandas.read_csv(url, names=names)
        return dataset

    # 提取样本特征集和类别集 划分训练/测试集
    def split_out_dataset(self, dataset):
        array = dataset.values  # 将数据库转换成数组形式
        X = array[:, 1:14].astype(float)  # 取特征数值列
        Y = array[:, 0]  # 取类别列
        validation_size = 0.20  # 验证集规模
        seed = 7
        # 分割数据集 测试/验证
        X_train, X_validation, Y_train, Y_validation = \
            model_selection.train_test_split(X, Y, test_size=validation_size, random_state=seed)
        return X_train, X_validation, Y_train, Y_validation

    """第一步:划分样本集"""

    # 提取样本 特征
    def split_out_attributes(self, X, Y):
        # 提取 每个类别的不同特征
        # c1 第一类的特征数组
        c1_1 = c1_2 = c1_3 = c1_4 = c1_5 = c1_6 = c1_7 = c1_8 = c1_9 = c1_10 = c1_11 = c1_12 = c1_13 = []
        c2_1 = c2_2 = c2_3 = c2_4 = c2_5 = c2_6 = c2_7 = c2_8 = c2_9 = c2_10 = c2_11 = c2_12 = c2_13 = []
        c3_1 = c3_2 = c3_3 = c3_4 = c3_5 = c3_6 = c3_7 = c3_8 = c3_9 = c3_10 = c3_11 = c3_12 = c3_13 = []
        for i in range(len(Y)):
            if (Y[i] == 1):
                c1_1.append(X[i, 0])
                c1_2.append(X[i, 1])
                c1_3.append(X[i, 2])
                c1_4.append(X[i, 3])
                c1_5.append(X[i, 4])
                c1_6.append(X[i, 5])
                c1_7.append(X[i, 6])
                c1_8.append(X[i, 7])
                c1_9.append(X[i, 8])
                c1_10.append(X[i, 9])
                c1_11.append(X[i, 10])
                c1_12.append(X[i, 11])
                c1_13.append(X[i, 12])
            elif (Y[i] == 2):
                # c2 第二类的特征数组
                c2_1.append(X[i, 0])
                c2_2.append(X[i, 1])
                c2_3.append(X[i, 2])
                c2_4.append(X[i, 3])
                c2_5.append(X[i, 4])
                c2_6.append(X[i, 5])
                c2_7.append(X[i, 6])
                c2_8.append(X[i, 7])
                c2_9.append(X[i, 8])
                c2_10.append(X[i, 9])
                c2_11.append(X[i, 10])
                c2_12.append(X[i, 11])
                c2_13.append(X[i, 12])
            elif (Y[i] == 3):
                # c3 第三类的特征数组
                c3_1.append(X[i, 0])
                c3_2.append(X[i, 1])
                c3_3.append(X[i, 2])
                c3_4.append(X[i, 3])
                c3_5.append(X[i, 4])
                c3_6.append(X[i, 5])
                c3_7.append(X[i, 6])
                c3_8.append(X[i, 7])
                c3_9.append(X[i, 8])
                c3_10.append(X[i, 9])
                c3_11.append(X[i, 10])
                c3_12.append(X[i, 11])
                c3_13.append(X[i, 12])
            else:
                pass

        return [c1_1, c1_2, c1_3, c1_4, c1_5, c1_6, c1_7, c1_8, c1_9, c1_10, c1_11, c1_12, c1_13,
                c2_1, c2_2, c2_3, c2_4, c2_5, c2_6, c2_7, c2_8, c2_9, c2_10, c2_11, c2_12, c2_13,
                c3_1, c3_2, c3_3, c3_4, c3_5, c3_6, c3_7, c3_8, c3_9, c3_10, c3_11, c3_12, c3_13]

    """因为符合多变量正态分布,所以需要(μ,∑)两个样本参数"""
    """第二步:计算样本期望μ和样本方差s"""

    # 计算样本期望
    def cal_mean(self, attributes):
        c1_1, c1_2, c1_3, c1_4, c1_5, c1_6, c1_7, c1_8, c1_9, c1_10, c1_11, c1_12, c1_13 \
            , c2_1, c2_2, c2_3, c2_4, c2_5, c2_6, c2_7, c2_8, c2_9, c2_10, c2_11, c2_12, c2_13 \
            , c3_1, c3_2, c3_3, c3_4, c3_5, c3_6, c3_7, c3_8, c3_9, c3_10, c3_11, c3_12, c3_13 = attributes

        # 第一类的期望值μ
        e_c1_1 = np.mean(c1_1)
        e_c1_2 = np.mean(c1_2)
        e_c1_3 = np.mean(c1_3)
        e_c1_4 = np.mean(c1_4)
        e_c1_5 = np.mean(c1_5)
        e_c1_6 = np.mean(c1_6)
        e_c1_7 = np.mean(c1_7)
        e_c1_8 = np.mean(c1_8)
        e_c1_9 = np.mean(c1_9)
        e_c1_10 = np.mean(c1_10)
        e_c1_11 = np.mean(c1_11)
        e_c1_12 = np.mean(c1_12)
        e_c1_13 = np.mean(c1_13)
        # 第二类的期望值μ
        e_c2_1 = np.mean(c2_1)
        e_c2_2 = np.mean(c2_2)
        e_c2_3 = np.mean(c2_3)
        e_c2_4 = np.mean(c2_4)
        e_c2_5 = np.mean(c2_5)
        e_c2_6 = np.mean(c2_6)
        e_c2_7 = np.mean(c2_7)
        e_c2_8 = np.mean(c2_8)
        e_c2_9 = np.mean(c2_9)
        e_c2_10 = np.mean(c2_10)
        e_c2_11 = np.mean(c2_11)
        e_c2_12 = np.mean(c2_12)
        e_c2_13 = np.mean(c2_13)
        # 第三类的期望值μ
        e_c3_1 = np.mean(c3_1)
        e_c3_2 = np.mean(c3_2)
        e_c3_3 = np.mean(c3_3)
        e_c3_4 = np.mean(c3_4)
        e_c3_5 = np.mean(c3_5)
        e_c3_6 = np.mean(c3_6)
        e_c3_7 = np.mean(c3_7)
        e_c3_8 = np.mean(c3_8)
        e_c3_9 = np.mean(c3_9)
        e_c3_10 = np.mean(c3_10)
        e_c3_11 = np.mean(c3_11)
        e_c3_12 = np.mean(c3_12)
        e_c3_13 = np.mean(c3_13)

        return [e_c1_1, e_c1_2, e_c1_3, e_c1_4, e_c1_5, e_c1_6, e_c1_7, e_c1_8, e_c1_9, e_c1_10, e_c1_11, e_c1_12,
                e_c1_13,
                e_c2_1, e_c2_2, e_c2_3, e_c2_4, e_c2_5, e_c2_6, e_c2_7, e_c2_8, e_c2_9, e_c2_10, e_c2_11, e_c2_12,
                e_c2_13,
                e_c3_1, e_c3_2, e_c3_3, e_c3_4, e_c3_5, e_c3_6, e_c3_7, e_c3_8, e_c3_9, e_c3_10, e_c3_11, e_c3_12,
                e_c3_13]

    # 计算样本方差
    def cal_var(self, attributes):
        c1_1, c1_2, c1_3, c1_4, c1_5, c1_6, c1_7, c1_8, c1_9, c1_10, c1_11, c1_12, c1_13 \
            , c2_1, c2_2, c2_3, c2_4, c2_5, c2_6, c2_7, c2_8, c2_9, c2_10, c2_11, c2_12, c2_13 \
            , c3_1, c3_2, c3_3, c3_4, c3_5, c3_6, c3_7, c3_8, c3_9, c3_10, c3_11, c3_12, c3_13 = attributes

        # 第一类的方差var
        var_c1_1 = np.var(c1_1)
        var_c1_2 = np.var(c1_2)
        var_c1_3 = np.var(c1_3)
        var_c1_4 = np.var(c1_4)
        var_c1_5 = np.var(c1_5)
        var_c1_6 = np.var(c1_6)
        var_c1_7 = np.var(c1_7)
        var_c1_8 = np.var(c1_8)
        var_c1_9 = np.var(c1_9)
        var_c1_10 = np.var(c1_10)
        var_c1_11 = np.var(c1_11)
        var_c1_12 = np.var(c1_12)
        var_c1_13 = np.var(c1_13)
        # 第二类的方差s
        var_c2_1 = np.var(c2_1)
        var_c2_2 = np.var(c2_2)
        var_c2_3 = np.var(c2_3)
        var_c2_4 = np.var(c2_4)
        var_c2_5 = np.var(c2_5)
        var_c2_6 = np.var(c2_6)
        var_c2_7 = np.var(c2_7)
        var_c2_8 = np.var(c2_8)
        var_c2_9 = np.var(c2_9)
        var_c2_10 = np.var(c2_10)
        var_c2_11 = np.var(c2_11)
        var_c2_12 = np.var(c2_12)
        var_c2_13 = np.var(c2_13)
        # 第三类的方差s
        var_c3_1 = np.var(c3_1)
        var_c3_2 = np.var(c3_2)
        var_c3_3 = np.var(c3_3)
        var_c3_4 = np.var(c3_4)
        var_c3_5 = np.var(c3_5)
        var_c3_6 = np.var(c3_6)
        var_c3_7 = np.var(c3_7)
        var_c3_8 = np.var(c3_8)
        var_c3_9 = np.var(c3_9)
        var_c3_10 = np.var(c3_10)
        var_c3_11 = np.var(c3_11)
        var_c3_12 = np.var(c3_12)
        var_c3_13 = np.var(c3_13)

        return [var_c1_1, var_c1_2, var_c1_3, var_c1_4, var_c1_5, var_c1_6, var_c1_7, var_c1_8, var_c1_9, var_c1_10,
                var_c1_11, var_c1_12, var_c1_13,
                var_c2_1, var_c2_2, var_c2_3, var_c2_4, var_c2_5, var_c2_6, var_c2_7, var_c2_8, var_c2_9, var_c2_10,
                var_c2_11, var_c2_12, var_c2_13,
                var_c3_1, var_c3_2, var_c3_3, var_c3_4, var_c3_5, var_c3_6, var_c3_7, var_c3_8, var_c3_9, var_c3_10,
                var_c3_11, var_c3_12, var_c3_13]

    # 计算先验概率P(Y=ck)
    def cal_prior_probability(self, Y):
        a = b = c = 0

        for i in Y:
            if (i == 1):
                a += 1
            elif (i == 2):
                b += 1
            elif (i == 3):
                c += 1
            else:
                pass

        pa = a / len(Y)
        pb = b / len(Y)
        pc = c / len(Y)
        return pa, pb, pc

    # 计算后验概率P(Y=ck|X)=P(X|Y=ck)*P(Y=ck)/∑
    def cal_posteriori_probability(self, X, Y, p, means, vars):
        pa, pb, pc = p

        e_c1_1, e_c1_2, e_c1_3, e_c1_4, e_c1_5, e_c1_6, e_c1_7, e_c1_8, e_c1_9, e_c1_10, e_c1_11, e_c1_12, e_c1_13 \
            , e_c2_1, e_c2_2, e_c2_3, e_c2_4, e_c2_5, e_c2_6, e_c2_7, e_c2_8, e_c2_9, e_c2_10, e_c2_11, e_c2_12, e_c2_13 \
            , e_c3_1, e_c3_2, e_c3_3, e_c3_4, e_c3_5, e_c3_6, e_c3_7, e_c3_8, e_c3_9, e_c3_10, e_c3_11, e_c3_12, e_c3_13 = means

        var_c1_1, var_c1_2, var_c1_3, var_c1_4, var_c1_5, var_c1_6, var_c1_7, var_c1_8, var_c1_9, var_c1_10, var_c1_11, var_c1_12, var_c1_13 \
            , var_c2_1, var_c2_2, var_c2_3, var_c2_4, var_c2_5, var_c2_6, var_c2_7, var_c2_8, var_c2_9, var_c2_10, var_c2_11, var_c2_12, var_c2_13 \
            , var_c3_1, var_c3_2, var_c3_3, var_c3_4, var_c3_5, var_c3_6, var_c3_7, var_c3_8, var_c3_9, var_c3_10, var_c3_11, var_c3_12, var_c3_13 = vars

        print('p:', p)
        print('means:', means)
        print('vars:', vars)

        # 分解十三维输入向量X=[X1,X2,X3...X13]为13个一维正态分布函数
        X1 = X[:, 0]
        X2 = X[:, 1]
        X3 = X[:, 2]
        X4 = X[:, 3]
        X5 = X[:, 4]
        X6 = X[:, 5]
        X7 = X[:, 6]
        X8 = X[:, 7]
        X9 = X[:, 8]
        X10 = X[:, 9]
        X11 = X[:, 10]
        X12 = X[:, 11]
        X13 = X[:, 12]

        # 分类正确数/分类错误数=>计算正确率
        true_test = 0
        false_test = 0

        # 遍历训练整个输入空间,计算后验概率并判决
        for i in range(len(X1)):
            # 计算后验概率=P(X|Y=C1)P(Y=C1)
            P_1 = stats.norm.pdf(
                X1[i], e_c1_1, var_c1_1) * stats.norm.pdf(
                X2[i], e_c1_2, var_c1_2) * stats.norm.pdf(
                X3[i], e_c1_3, var_c1_3) * stats.norm.pdf(
                X4[i], e_c1_4, var_c1_4) * stats.norm.pdf(
                X5[i], e_c1_5, var_c1_5) * stats.norm.pdf(
                X6[i], e_c1_6, var_c1_6) * stats.norm.pdf(
                X7[i], e_c1_7, var_c1_7) * stats.norm.pdf(
                X8[i], e_c1_8, var_c1_8) * stats.norm.pdf(
                X9[i], e_c1_9, var_c1_9) * stats.norm.pdf(
                X10[i], e_c1_10, var_c1_10) * stats.norm.pdf(
                X11[i], e_c1_11, var_c1_11) * stats.norm.pdf(
                X12[i], e_c1_12, var_c1_12) * stats.norm.pdf(
                X13[i], e_c1_13, var_c1_13) * pa
            # 计算后验概率=P(X|Y=C2)P(Y=C2)
            P_2 = stats.norm.pdf(
                X1[i], e_c2_1, var_c2_1) * stats.norm.pdf(
                X2[i], e_c2_2, var_c2_2) * stats.norm.pdf(
                X3[i], e_c2_3, var_c2_3) * stats.norm.pdf(
                X4[i], e_c2_4, var_c2_4) * stats.norm.pdf(
                X5[i], e_c2_5, var_c2_5) * stats.norm.pdf(
                X6[i], e_c2_6, var_c2_6) * stats.norm.pdf(
                X7[i], e_c2_7, var_c2_7) * stats.norm.pdf(
                X8[i], e_c2_8, var_c2_8) * stats.norm.pdf(
                X9[i], e_c2_9, var_c2_9) * stats.norm.pdf(
                X10[i], e_c2_10, var_c2_10) * stats.norm.pdf(
                X11[i], e_c2_11, var_c2_11) * stats.norm.pdf(
                X12[i], e_c2_12, var_c2_12) * stats.norm.pdf(
                X13[i], e_c2_13, var_c2_13) * pb
            # 计算后验概率=P(X|Y=C3)P(Y=C3)
            P_3 = stats.norm.pdf(
                X1[i], e_c3_1, var_c3_1) * stats.norm.pdf(
                X2[i], e_c3_2, var_c3_2) * stats.norm.pdf(
                X3[i], e_c3_3, var_c3_3) * stats.norm.pdf(
                X4[i], e_c3_4, var_c3_4) * stats.norm.pdf(
                X5[i], e_c3_5, var_c3_5) * stats.norm.pdf(
                X6[i], e_c3_6, var_c3_6) * stats.norm.pdf(
                X7[i], e_c3_7, var_c3_7) * stats.norm.pdf(
                X8[i], e_c3_8, var_c3_8) * stats.norm.pdf(
                X9[i], e_c3_9, var_c3_9) * stats.norm.pdf(
                X10[i], e_c3_10, var_c3_10) * stats.norm.pdf(
                X11[i], e_c3_11, var_c3_11) * stats.norm.pdf(
                X12[i], e_c3_12, var_c3_12) * stats.norm.pdf(
                X13[i], e_c3_13, var_c3_13) * pc

            # 计算判别函数,选取概率最大的类
            max_P = max(P_1, P_2, P_3)
            # 输出分类结果,并检测正确率
            if (max_P == P_1):
                if (Y[i] == 1):
                    print('分为第一类,正确')
                    true_test += 1
                else:
                    print('分为第一类,错误')
                    false_test += 1
            elif (max_P == P_2):
                if (Y[i] == 2):
                    print('分为第二类,正确')
                    true_test += 1
                else:
                    print('分为第二类,错误')
                    false_test += 1
            elif (max_P == P_3):
                if (Y[i] == 3):
                    print('分为第三类,正确')
                    true_test += 1
                else:
                    print('分为第三类,错误')
                    false_test += 1
            else:
                print('未分类')
                false_test += 1
        # 打印分类正确率
        print('训练正确率为:', (true_test / (true_test + false_test)))

        # 模板方法对照

    def cal_dataset(self, X_train, Y_train):
        # Test options and evaluation metric
        seed = 7
        scoring = 'accuracy'
        # Check Algorithms
        model = GaussianNB()
        name = 'bayes classifier'
        # 建立K折交叉验证 10倍
        kfold = model_selection.KFold(n_splits=10, random_state=seed)
        # cross_val_score() 对数据集进行指定次数的交叉验证并为每次验证效果评测
        cv_results = \
            model_selection.cross_val_score(model, X_train, Y_train, cv=kfold, scoring=scoring)
        results = cv_results
        msg = "%s: %f (%f)" % (name + '精度', cv_results.mean(), cv_results.std())
        print(msg)

        # Show Algorithms
        dataresult = pandas.DataFrame(results)
        dataresult.plot(title='Bayes accuracy analysis', kind='density', subplots=True, layout=(1, 1), sharex=False,
                        sharey=False)
        dataresult.hist()
        plt.show()

bayes = Bayes_Test()

dataset = bayes.load_dataset()
# 划分训练集 测试集
X_train, X_validation, Y_train, Y_validation = bayes.split_out_dataset(dataset)
print('得到的X_train', X_train)
print('得到的Y_train', Y_train)

# 分割属性--训练集
attributes = bayes.split_out_attributes(X_train, Y_train)
print('得到的训练集', attributes)

# 计算期望--训练集
means = bayes.cal_mean(attributes)
print('得到的means', means)

# 计算方差--训练集
vars = bayes.cal_var(attributes)
print('得到的vars', vars)

# 计算先验概率--训练集
prior_p = bayes.cal_prior_probability(Y_train)
# 验证分类准确性--测试集
bayes.cal_posteriori_probability(X_train, Y_train, prior_p, means, vars)

# 模板方法--性能对比
bayes.cal_dataset(X_validation,Y_validation)