[数据挖掘] 朴素贝叶斯 以及西瓜集特征工程

本文介绍了朴素贝叶斯的基本思想和分类过程,并通过西瓜数据集进行实例讲解。文章涵盖数据集分析、朴素贝叶斯分类器的训练与预测,以及不同版本的代码改进,包括拉普拉斯平滑和特征工程,如OneHotEncoder和LabelEncoder的使用。还探讨了pandas在数据处理中的应用和一些操作技巧。
摘要由CSDN通过智能技术生成

朴素贝叶斯的基本思想

  • 先验概率: 通过已知事实, 推论出未知事务出现的概率
    例如: 通过硬币有两面, 推论出抛一次硬币可能出现正面的概率
  • 后验概率: 通过结果, 推论出导致该结果的原因的概率
    例如: 通过硬币抛出来之后是正面, 需要你来判断该硬币被你做手法了的概率

关于先验概率 与 后验概率的理解: https://www.cnblogs.com/yemanxiaozu/p/7680761.html

  • 贝叶斯公式:
    在这里插入图片描述
    • 其中, B 是 该事件最后的结果, A 是表示导致该结果的原因, 再结合我们之前对后验概率的理解, 可以知道, 贝叶斯公式的结果就是导致结果B出现的可能性
    • 在机器学习中, 对于一个需要预测的数据, 我们知道的是它的各种已知信息相当于公式中的A, 而我们要求的是最后对他的各个分类的概率, 这个分类就相当于公式中的 B, 于是 我们的公式可以表示为:
      在这里插入图片描述
  • 机器学习—朴素贝叶斯: 对于上述的贝叶斯公式, 其中已知的 A 可以看作该数据的特征, 而我们假定该数据的各个特征是独立的, 所以对于p(特征|类别), 我们可以分解为 p(特征1|类别) * p(特征2|类别) * p(特征3|类别) … 这就是朴素的意思, 而对于需预测的数据来说, 我们p(特征), p(类别) 是很容易通过大量数据得到的已知值
    • 引用西瓜书上说的:
      其中ck表示第k 个分类, xj 表示第j个特征值, Y是该数据最终的分类结果
      在这里插入图片描述
    1. 因此 我们需要训练的是什么呢:
      每个特征属于每个分类的概率
    2. 通过被预测数据的特征, 从训练出来的分类器中查找每个特征在每个分类的概率相乘(朴素)
    3. 得到该数据最终属于每个分类的概率, 选出概率最大的为其最后的分类
  • 本文算法代码只讨论二分类情况

朴素贝叶斯分类的过程

  1. 数据获取: 任意方式获取
  2. 数据分析: 得到其独立同分布的特征, 应用朴素这一条件
  3. 训练过程:
    • 若是离散值: 获取每一个特征在每一个分类下的可能性
    • 若是连续值: 假定其符合正态分布, 计算其一维正态分布值:
      在这里插入图片描述
  4. 预测过程: 获取数据各个特征, 计算其属于每个分类的概率, 选出最大概率作为其分类结果
  5. 模型评估: 本章采用 留出法, k折交叉验证法(留一法), 自助法, 结果为
    [真正例, 假正例, 真负例, 假负例]
  6. 性能评估: 准确率

数据集:

1,青绿,蜷缩,浊响,清晰,凹陷,硬滑,0.697,0.46,是
2,乌黑,蜷缩,沉闷,清晰,凹陷,硬滑,0.774,0.376,是
3,乌黑,蜷缩,浊响,清晰,凹陷,硬滑,0.634,0.264,是
4,青绿,蜷缩,沉闷,清晰,凹陷,硬滑,0.608,0.318,是
5,浅白,蜷缩,浊响,清晰,凹陷,硬滑,0.556,0.215,是
6,青绿,稍蜷,浊响,清晰,稍凹,软粘,0.403,0.237,是
7,乌黑,稍蜷,浊响,稍糊,稍凹,软粘,0.481,0.149,是
8,乌黑,稍蜷,浊响,清晰,稍凹,硬滑,0.437,0.211,是
9,乌黑,稍蜷,沉闷,稍糊,稍凹,硬滑,0.666,0.091,否
10,青绿,硬挺,清脆,清晰,平坦,软粘,0.243,0.267,否
11,浅白,硬挺,清脆,模糊,平坦,硬滑,0.245,0.057,否
12,浅白,蜷缩,浊响,模糊,平坦,软粘,0.343,0.099,否
13,青绿,稍蜷,浊响,稍糊,凹陷,硬滑,0.639,0.161,否
14,浅白,稍蜷,沉闷,稍糊,凹陷,硬滑,0.657,0.198,否
15,乌黑,稍蜷,浊响,清晰,稍凹,软粘,0.36,0.37,否
16,浅白,蜷缩,浊响,模糊,平坦,硬滑,0.593,0.042,否
17,青绿,蜷缩,沉闷,稍糊,稍凹,硬滑,0.719,0.103,否
  • 特征包含了离散值与连续值, 最后是数据标签
  • 可看到连续值已经处于 (0,1)之间了, 因此不需要归一化处理

版本1

  • 这个版本只完成了最基础的西瓜数据集的朴素贝叶斯分类
  • 写的时候发现每次预测都要训练, 然后, 想到把训练与预测分类, 就可以多次使用分类器了, 然后有了版本2

记录一下代码有多烂:

import numpy as np
import math


def label_count(dataset):
    """
    计算每个分类结果的概率
    :param dataset:[ [feat], [feat], [feat], ... , [label], ]
    :return: p(label) : {label: prob, }
    """
    label = {
   }
    for i in dataset:
        if i[-1] not in label.keys():
            label[i[-1]] = 0
        label[i[-1]] += 1

    return label


def feat_count(dataset, item, label, labels):
    """
    计算某个特征向量被分类为label的概率
    :param dataset:
    :param labels 每种分类的概率
    :param item: 特征向量
    :return:
    """
    feat_num = np.array([0 for _ in item], np.float32)
    for i in range(len(item)):
        if isinstance(item[i], (float, int)):
            set_i = np.array([j[i] for j in dataset])
            u = set_i.mean()
            std = set_i.std()
            feat_num[i] = (1/(math.sqrt(2*math.pi)*std)) * math.pow(math.e, -1*(feat_num[i] - u)**2 / (2*(std**2)))
        else:
            for j in dataset:
                if item[i] == j[i] and j[-1] == label:
                    feat_num[i] += 1
            feat_num[i] /= labels[label]
    return feat_num


def classification(item, dataset):
    """
    返回属于每一种分类的可能性
    :param item:
    :param dataset:
    :return:
    """
    labels = label_count(dataset)
    data_num = len(dataset)
    ans = {
   }
    for label in labels:
        feat_num = feat_count(dataset, item, label, labels)
        ans[label] = 1
        for i in feat_num:
            ans[label] *= i
        ans[label] *= float(labels[label]) / float(data_num)
    return sorted(ans.items(), key=lambda j: j[1], reverse=True)


def fun(i):
        i = i.strip()
        try:
            i = float(i)
        except ValueError:
            pass
        return i


def read_data(path):
    dataset = []
    with open(path, 'r', encoding='utf8') as f:
        for line in f.readlines():
            split_ = line.strip().split(',')[1:]
            dataset.append([i for i in map(fun, split_)])
    return dataset


if __name__ == '__main__':
    path = "xigua.txt"
    dataset = read_data(path)

    pre_data = '青绿,蜷缩,浊响,清晰,凹陷,硬滑,0.697,  0.460'
    item = [i for i in pre_data.strip().split(',')]
    item = [i for i in map(fun, item)]

    print(item)
    l = classification(item, dataset)
    print(l)

结果:
在这里插入图片描述

评估

把数据集放进去, 分出测试集与训练集, 进行评估即可
结果:
[真正例, 假正例, 真负例, 假负例]
在这里插入图片描述

版本2

  • 这个版本把训练过程 与测试过程分开了
  • 加入了拉普拉斯假设: 即把为0的特征进行+1, 避免了该分类可能性为0
  • 最后给每个特征概率的结果相乘改成了: 最后求log后相加, 避免了特征很多的时候出现的大误差
  • 写的时候想到了是不是可以用矩阵运算来避免遍历过程, 以及面向对象.于是出现了版本3

训练

  • 训练返回结果的数据结构:
    1. 离散型, feat_pos_count, feat_neg_count, 表示分类结果为正例和负例的计数
      {
      特征1:{value1: count, value2: count},
      特征2:{value1: count, value2: count},

      }
    2. 连续型, numer_feat
      {
      连续型特征: {‘u’: 平均数, ‘std’: 标准差},

      }
    3. pos_prob: 正例占总数的可能性, 负例直接 1-pos_prob
  • 训练过程就是计数而已, 很简单
def n_attribute(u, std, x):
    return (1/(sqrt(2*pi)*std)) * pow(e, -1*(x - u)**2 / (2*(std**2)))


def train_bayesian_2_classify(dataset):
    """
    2分类器, 1--正, 0--负
    训练贝叶斯分类器, 即得到每个特征值的条件概率
    :param dataset:最后一列是label 其他作为特征值
    :return:
    """
    # 初始化每个特征有一个计数,避免最后概率为0. 拉普拉斯校准
    feat_num = len(dataset[0])-1
    feat_pos_count = [dict() for _ in range(feat_num)]
    feat_neg_count = [dict() for _ in range(feat_num)]
    # 获取正负例数
    pos_num = 0.0
    neg_num = 0.0
    data_num = len(dataset)
    numer_feat = []
    for i in range(feat_num):
        if isinstance(dataset[0][i], (float,)):
            numer_feat.append(i)

    for i in range(data_num):
        for j in range(feat_num):
            if j not in numer_feat:
                if dataset[
  • 7
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
朴素贝叶斯是一种基于贝叶斯定理的分类算法,可以用于文本分类、垃圾邮件过滤、情感分析等任务。在这里,我们以西瓜数据集为例,介绍朴素贝叶斯的应用。 首先,让我们来了解一下西瓜数据集。这是一个经典的二分类数据集,包含了17个样本和8个特征,其中7个是离散型特征,1个是连续型特征数据集中每个样本都被标记为“好瓜”或“坏瓜”。这里我们以“密度”和“含糖率”两个特征为例,来演示如何使用朴素贝叶斯进行分类。 首先,我们需要将数据集按照“好瓜”和“坏瓜”进行分类,然后计算每个类别的先验概率。我们可以得到: - P(好瓜) = 8/17 - P(坏瓜) = 9/17 接下来,我们需要计算每个特征在每个类别下的条件概率。对于连续型特征,我们可以使用高斯分布进行估计。对于离散型特征,我们可以使用多项式分布进行估计。在这里,我们假设“密度”和“含糖率”都是连续型特征,使用高斯分布进行估计。我们可以得到: - P(密度|好瓜) ~ N(0.414, 0.016) - P(密度|坏瓜) ~ N(0.368, 0.034) - P(含糖率|好瓜) ~ N(0.320, 0.014) - P(含糖率|坏瓜) ~ N(0.319, 0.027) 其中,N(μ, σ2)表示均值为μ,方差为σ2的高斯分布。注意,这里我们使用了极大似然估计来估计高斯分布的参数。 现在,我们已经计算了所有的先验概率和条件概率。对于一个新的样本,我们可以根据贝叶斯定理来计算它属于“好瓜”和“坏瓜”的后验概率,然后选择后验概率较大的类别作为预测结果。具体地,我们可以计算: - P(好瓜|密度=d, 含糖率=s) ∝ P(好瓜) * P(密度=d|好瓜) * P(含糖率=s|好瓜) - P(坏瓜|密度=d, 含糖率=s) ∝ P(坏瓜) * P(密度=d|坏瓜) * P(含糖率=s|坏瓜) 其中,d和s分别表示样本的密度和含糖率。由于我们只需要比较后验概率的大小,所以可以省略掉分母部分。 最终,我们可以选择后验概率较大的类别作为预测结果。具体地,如果P(好瓜|密度=d, 含糖率=s) > P(坏瓜|密度=d, 含糖率=s),则预测结果为“好瓜”,否则为“坏瓜”。 这就是朴素贝叶斯西瓜数据集上的应用。当然,这只是一个简单的例子,实际中可能需要对特征进行筛选、调整先验概率、处理缺失值等问题,才能得到更好的分类结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值