西瓜书课后题7.6(AODE)

题目

试编程实现AODE分类器,并以西瓜数据集3.0位训练集,对p.151的“测1”样本进行判别。

编号色泽根蒂敲声纹理脐部触感密度含糖率好瓜
测1青绿蜷缩浊响清晰凹陷硬滑0.6970.460

这个数据的真实类别为好瓜,在上一题用朴素贝叶斯也测试过。

原理

这实际上是一个半朴素贝叶斯分类器。首先什么叫朴素贝叶斯分类器,即采用了“”属性条件独立性假设”。其含义为,每个属性之间是没有关系的,是独立的。基于上述假设,如果我们有样本 x x x,它的类为 c c c, 我们就有 P ( x ∣ c ) = P ( x 1 , x 2 ⋯   , x d ∣ c ) = ∏ i = 1 d P ( x i ∣ c ) P(x|c) = P(x1,x2\cdots,x_d|c)=\prod_{i=1}^dP(x_i|c) P(xc)=P(x1,x2,xdc)=i=1dP(xic) x i x_i xi表示第 i i i个属性的一个取值,比如可以是色泽属性的青绿,也可以是根蒂属性的蜷缩。所谓半朴素贝叶斯分类器的意思为不光简单的认为属性之间是独立的,而是考虑一个属性和另一个属性可能是相关的。AODE意思是只考虑一个属性一次只与一个属性相关的情况。即 P ( x ∣ c ) = ∏ i = 1 d P ( x i ∣ c , x j ) P(x|c) =\prod_{i=1}^dP(x_i|c,x_j) P(xc)=i=1dP(xic,xj),即对于类c和第j个属性取某值的情况下,第i个属性取某值的概率。具体参考西瓜书。

代码

import numpy as np
import matplotlib.pyplot as plt
from pylab import *
import operator

# 特征字典,后面用到了好多次,干脆当全局变量了
featureDic = {
    '色泽': ['浅白', '青绿', '乌黑'],
    '根蒂': ['硬挺', '蜷缩', '稍蜷'],
    '敲声': ['沉闷', '浊响', '清脆'],
    '纹理': ['清晰', '模糊', '稍糊'],
    '脐部': ['凹陷', '平坦', '稍凹'],
    '触感': ['硬滑', '软粘']}


def getDataSet():
    """
    get watermelon data set 3.0.
    :return: 编码好的数据集以及特征的字典。
    """
    dataSet = [
        ['青绿', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', 0.697, 0.460, 1],
        ['乌黑', '蜷缩', '沉闷', '清晰', '凹陷', '硬滑', 0.774, 0.376, 1],
        ['乌黑', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', 0.634, 0.264, 1],
        ['青绿', '蜷缩', '沉闷', '清晰', '凹陷', '硬滑', 0.608, 0.318, 1],
        ['浅白', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', 0.556, 0.215, 1],
        ['青绿', '稍蜷', '浊响', '清晰', '稍凹', '软粘', 0.403, 0.237, 1],
        ['乌黑', '稍蜷', '浊响', '稍糊', '稍凹', '软粘', 0.481, 0.149, 1],
        ['乌黑', '稍蜷', '浊响', '清晰', '稍凹', '硬滑', 0.437, 0.211, 1],
        ['乌黑', '稍蜷', '沉闷', '稍糊', '稍凹', '硬滑', 0.666, 0.091, 0],
        ['青绿', '硬挺', '清脆', '清晰', '平坦', '软粘', 0.243, 0.267, 0],
        ['浅白', '硬挺', '清脆', '模糊', '平坦', '硬滑', 0.245, 0.057, 0],
        ['浅白', '蜷缩', '浊响', '模糊', '平坦', '软粘', 0.343, 0.099, 0],
        ['青绿', '稍蜷', '浊响', '稍糊', '凹陷', '硬滑', 0.639, 0.161, 0],
        ['浅白', '稍蜷', '沉闷', '稍糊', '凹陷', '硬滑', 0.657, 0.198, 0],
        ['乌黑', '稍蜷', '浊响', '清晰', '稍凹', '软粘', 0.360, 0.370, 0],
        ['浅白', '蜷缩', '浊响', '模糊', '平坦', '硬滑', 0.593, 0.042, 0],
        ['青绿', '蜷缩', '沉闷', '稍糊', '稍凹', '硬滑', 0.719, 0.103, 0]
    ]

    features = ['色泽', '根蒂', '敲声', '纹理', '脐部', '触感', '密度', '含糖量']
    # features = ['color', 'root', 'knocks', 'texture', 'navel', 'touch', 'density', 'sugar']

    # #得到特征值字典,本来用这个生成的特征字典,还是直接当全局变量方便
    # featureDic = {}
    # for i in range(len(features)):
    #     featureList = [example[i] for example in dataSet]
    #     uniqueFeature = list(set(featureList))
    #     featureDic[features[i]] = uniqueFeature

    # 每种特征的属性个数
    numList = []  # [3, 3, 3, 3, 3, 2]
    for i in range(len(features) - 2):
        numList.append(len(featureDic[features[i]]))

    dataSet = np.array(dataSet)
    return dataSet, features


def AODE(dataSet, data, features):
    """
    AODE(Averaged One-Dependent Estimator)。意思为尝试将每个属性作为超父来构建SPODE。
    :param dataSet:
    :param data:
    :param features:
    :return:
    """
    m, n = dataSet.shape
    n = n - 3       # 特征不取连续值的属性,如密度和含糖量。
    pDir = {}       # 保存三个值。好瓜的可能性,坏瓜的可能性,和预测的值。
    for classLabel in ["好瓜", "坏瓜"]:
        P = 0.0
        if classLabel == "好瓜":
            sign = '1'
        else:
            sign = '0'
        extrDataSet = dataSet[dataSet[:, -1] == sign]    # 抽出类别为sign的数据
        for i in range(n):                               # 对于第i个特征
            xi = data[i]
            # 计算classLabel类,第i个属性上取值为xi的样本对总数据集的占比
            Dcxi = extrDataSet[extrDataSet[:, i] == xi]  # 第i个属性上取值为xi的样本数
            Ni = len(featureDic[features[i]])            # 第i个属性可能的取值数
            Pcxi = (len(Dcxi) + 1) / float(m + 2 * Ni)
            # 计算类别为c且在第i和第j个属性上分别为xi和xj的样本,对于类别为c属性为xi的样本的占比
            mulPCond = 1
            for j in range(n):
                xj = data[j]
                Dcxij = Dcxi[Dcxi[:, j] == xj]
                Nj = len(featureDic[features[j]])
                PCond = (len(Dcxij) + 1) / float(len(Dcxi) + Nj)
                mulPCond *= PCond
            P += Pcxi * mulPCond
        pDir[classLabel] = P

    if pDir["好瓜"] > pDir["坏瓜"]:
        preClass = "好瓜"
    else:
        preClass = "坏瓜"

    return pDir["好瓜"], pDir["坏瓜"], preClass


def calcAccRate(dataSet, features):
    """
    计算准确率
    :param dataSet:
    :param features:
    :return:
    """
    cnt = 0
    for data in dataSet:
        _, _, pre = AODE(dataSet, data, features)
        if (pre == '好瓜' and data[-1] == '1') \
            or (pre == '坏瓜' and data[-1] == '0'):
            cnt += 1
    return cnt / float(len(dataSet))


def main():
    dataSet, features = getDataSet()
    pG, pB, pre = AODE(dataSet, dataSet[0], features)
    print("pG = ", pG)
    print("pB = ", pB)
    print("pre = ", pre)
    print("real class = ", dataSet[0][-1])
    print(calcAccRate(dataSet, features))


if __name__ == '__main__':
    main()

输出结果

在这里插入图片描述
可以发现,半朴素贝叶斯,在该数据集下,能取到比朴素贝叶斯更好的效果。

  • 10
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值