朴素贝叶斯分类器(附代码)

转载

原文还包含一定的理论基础我没复制过来,我只在代码基础上加了注释。注释比较基础也比较详细,我也是初学因此该注释为小白学习自用,有错误敬请指出。

import math
import random

all_num = 0     # 样本总数
cla_num = {}       # 字典,分类的集合,里面是类别
cla_tag_num = {}   # 字典,分类的集合,里面元素还有字典
landa = 0.6  # 拉普拉斯修正值
# tag:某个特征
# features:特征的集合
# clu:某个分类


def train(features, clu):  # 训练 ,每次插入一条数据
    # 插入分类
    global all_num
    all_num += 1
    if clu in cla_num:  # 是否已存在该分类
        cla_num[clu] += 1      # 类别clu样本数加1
    else:
        cla_num[clu] = 1
    if clu not in cla_tag_num:
        cla_tag_num[clu] = {}    # 类别clu也是字典,里面元素为{特征(tag):包含该特征样本数}
    # 插入标签
    tmp_tags = cla_tag_num[clu]  # 将上文提到的字典里的字典拿出来
    for tag in features:
        if tag in tmp_tags:
            tmp_tags[tag] += 1
        else:
            tmp_tags[tag] = 1
   # 更新了全局变量,就不用返回值了

def P_C(cla):  # 计算分类 cla 的先验概率
    return cla_num[cla] / all_num    #发生cla数量/总数

def P_W_C(tag, cla):  # 计算分类 cla 中标签 tag 的后验概率
    tmp_tags = cla_tag_num[cla]  # 浅拷贝,用作别名
    if tag not in cla_tag_num[cla]:  # 所有发生cla的个体都不包含tag特征
        return landa / (cla_num[cla] + len(tmp_tags) * landa)  # 拉普拉斯修正
    return (tmp_tags[tag] + landa) / (cla_num[cla] + len(tmp_tags) * landa)


def test(test_tags):  # 测试
    res = ''  # 结果
    res_P = None
    for cla in cla_num.keys():    # 就循环两遍,先求'是'的值再求'否'的,.key的意思是求只取键值对的键
        log_P_W_C = 0
        for tag in test_tags:
            log_P_W_C += math.log(P_W_C(tag, cla), 2)  # 将P(wi|Ci)取对数,乘法变加法,P(w|Ci)=ΣP(wi|Ci)
        tmp_P = log_P_W_C + math.log(P_C(cla), 2)  # P(w|Ci) * P(Ci)
        if res_P is None:
            res = cla
            res_P = tmp_P    # 第一个求出的结果存在res_P里
        if tmp_P > res_P:
            res = cla
            res_P = tmp_P
    return res, res_P


def create_MarriageData():
    p0 = ['青绿', '乌黑', '浅白']
    p1 = ['蜷缩', '稍蜷', '硬挺']
    p2 = ['浊响', '沉闷', '清脆']
    p3 = ['清晰', '稍糊', '模糊']
    p4 = ['凹陷', '稍凹', '平坦']
    p5 = ['硬滑', '软粘']
    dataset = []  # 创建样本
    dataset.append(random.choice(p0))  # 每个样本随机选择长相
    dataset.append(random.choice(p1))  # 同理,随机选择性格
    dataset.append(random.choice(p2))  # 同理
    dataset.append(random.choice(p3))  # 同理
    dataset.append(random.choice(p4))  # 同理
    dataset.append(random.choice(p5))  # 同理
    print("随机产生西瓜为:", dataset)
    return dataset


def beyesi():
    # 训练模型
    data = [['青绿', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', '是'],
            ['乌黑', '蜷缩', '沉闷', '清晰', '凹陷', '硬滑', '是'],
            ['乌黑', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', '是'],
            ['青绿', '蜷缩', '沉闷', '清晰', '凹陷', '硬滑', '是'],
            ['浅白', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', '是'],
            ['青绿', '稍蜷', '浊响', '清晰', '稍凹', '软粘', '是'],
            ['乌黑', '稍蜷', '浊响', '稍糊', '稍凹', '软粘', '是'],
            ['乌黑', '稍蜷', '浊响', '清晰', '稍凹', '硬滑', '是'],
            ['乌黑', '稍蜷', '沉闷', '稍糊', '稍凹', '硬滑', '否'],
            ['青绿', '硬挺', '清脆', '清晰', '平坦', '软粘', '否'],
            ['浅白', '硬挺', '清脆', '模糊', '平坦', '硬滑', '否'],
            ['浅白', '蜷缩', '浊响', '模糊', '平坦', '软粘', '否'],
            ['浅白', '稍蜷', '浊响', '稍糊', '凹陷', '硬滑', '否'],
            ['浅白', '稍蜷', '沉闷', '稍糊', '凹陷', '硬滑', '否'],
            ['乌黑', '稍蜷', '沉闷', '稍糊', '稍凹', '软粘', '否'],
            ['浅白', '蜷缩', '浊响', '模糊', '平坦', '硬滑', '否'],
            ['青绿', '蜷缩', '沉闷', '稍糊', '稍凹', '硬滑', '否']]
    for x in data:
        train(x[0:6], x[-1])     #[0:6]不包括6,[-1]即倒数第一个元素

# 测试模型
#for x in data:
#    print('测试结果:', test(x[0:6]))
if __name__ == '__main__':
    beyesi()  # 创建朴素贝叶斯分类
    # 单例测试模型
    testcs = ['青绿', '蜷缩', '浊响', '清晰', '凹陷', '硬滑']
    print("单例测试为:", testcs)
    print('测试结果:', test(testcs))
    # 随机测试模型
    for i in range(1, 5):
        print('测试结果:', test(create_MarriageData()))

你可能感兴趣的:(分类,python,机器学习)