朴素贝叶斯分类算法及其实现

对于分类任务来说,使用概率有时要比使用硬规则更为有效,朴素贝叶斯即是一种基于概率论进行分类的方法。

一、基础理论

1、朴素贝叶斯的优缺点
优点:在数据较少时仍有效,可处理多类别问题
缺点:对输入数据准备方式敏感
适用数据类型:标称型数据
2、 贝叶斯决策理论
选择具有最高概率的决策
3、 贝叶斯准则
在这里插入图片描述4、可在任意场景中使用朴素贝叶斯分类器,常见的应用是文档分类(比如垃圾邮件分类)
5、“朴素”指的是整个形式化过程只做最原始、最简单的假设:
(1)各特征之间相互独立
(2)每个特征同等重要
6、用朴素贝叶斯计算条件概率的伪代码为:在这里插入图片描述
7、尽管条件独立性假设并不正确,但朴素贝叶斯仍是一种有效的分类器。

二、代码实现

2.1 加载样例数据
def load_dataset():
    '''
    构建单词数据集和标签
    :return: 单词数据集,标签
    '''
    words_set = [['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
                 ['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
                 ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
                 ['stop', 'posting', 'stupid', 'worthless', 'garbage'],
                 ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
                 ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
    label_list = [0, 1, 0, 1, 0, 1]
    return words_set, label_list
2.2 构建词汇表
def creat_vocab_list(data_set):
    '''
    依据数据集构建词汇表
    :param data_set: 数据集
    :return: 词汇列表
    '''
    vocab_set = set()
    for data in data_set:
        vocab_set = vocab_set | set(data)  # 并集
    return list(vocab_set)
2.3 构建词向量
def words_to_vector(vocab_list, word_list):
    '''
    获取词向量
    :param vocab_list: 词汇列表
    :param word_list: 单词列表
    :return: 词向量
    '''
    words_vector = [0] * len(vocab_list)
    for word in word_list:
        if word in vocab_list:
            words_vector[vocab_list.index(word)] += 1
        else:
            print('the word %s is not in my vocabulary' % word)
    return words_vector
2.4 分类器训练函数
def train_bayes(doc_matrix, label_list):
    '''
    分类器训练函数
    :param doc_matrix: 文档矩阵
    :param label_list:  标签向量
    :return:
    '''
    num_docs = len(doc_matrix)  # 词向量个数 行
    num_words = len(doc_matrix[0])  # 词汇数量  列
    prob_1 = np.sum(label_list) / len(label_list)  # 类别是 1 的概率
    p0_vector = np.ones(num_words)
    p1_vector = np.ones(num_words)
    p0_sum = 2.0
    p1_sum = 2.0
    for i in range(num_docs):
        if label_list[i] == 1:
            p1_vector += doc_matrix[i]
            p1_sum += np.sum(doc_matrix[i])
        else:
            p0_vector += doc_matrix[i]
            p0_sum += np.sum(doc_matrix[i])
    p1_vector /= p1_sum
    p0_vector /= p0_sum
    return np.log(p1_vector), np.log(p0_vector), prob_1   # 转换为以e为底的对数形式,防止下溢

2.5 分类函数

def classify_bayes(test_vector, p1_vector, p0_vector, prob_1):
    '''
    用贝叶斯函数进行分类
    :param test_vector: 测试词向量
    :param p1_vector:  类1概率向量
    :param p0_vector:  类0概率向量
    :param prob_1:  类1概率
    :return: 测试词向量类别
    '''
    p1 = np.sum(p1_vector * test_vector) + np.log(prob_1)
    p0 = np.sum(p0_vector * test_vector) + np.log(1 - prob_1)
    if p1 > p0:
        return 1
    else:
        return 0

2.6 测试

def test_bayes():
    '''
    测试贝叶斯分类器的分类效果
    :return:
    '''
    words_set, label_list = load_dataset()
    vocab_list = creat_vocab_list(words_set)
    doc_matrix = [words_to_vector(vocab_list, word) for word in words_set]
    p1_vector, p0_vector, prob_1 = train_bayes(doc_matrix, label_list)

    test_words = ['love', 'my', 'dalmation']
    test_vector = np.array(words_to_vector(vocab_list, test_words))
    print(test_words, 'classified as: ', classify_bayes(test_vector, p1_vector, p0_vector, prob_1))

    test_words = ['stupid', 'garbage']
    test_vector = np.array(words_to_vector(vocab_list, test_words))
    print(test_words, 'classified as: ', classify_bayes(test_vector, p1_vector, p0_vector, prob_1))

输出结果为:
[‘love’, ‘my’, ‘dalmation’] classified as: 0
[‘stupid’, ‘garbage’] classified as: 1

2.7 文本文件解析

import re
def text_sparse(text):
    '''
    解析文件
    :param text: 文件
    :return: 解析为合适的单词列表
    '''
    list_token = re.split('\\W*', text)    # 除单词、数字外的任意字符串均为分隔符,应用正则表达式
    return [token.lower() for token in list_token if len(token) > 2]

2.8 垃圾邮件分类

import random
def spam_test():
    '''
    垃圾邮件测试
    :return: 错误率
    '''
    doc_list = []
    class_list = []
    full_text = []
    for i in range(1, 26):
        word_list = text_sparse(open('./email/spam/%d.txt' % i).read())
        doc_list.append(word_list)
        full_text.extend(word_list)
        class_list.append(1)
        word_list = text_sparse(open('./email/ham/%d.txt' % i).read())
        doc_list.append(word_list)
        full_text.extend(word_list)
        class_list.append(0)
    vocab_list = creat_vocab_list(doc_list)
    train_index = list(range(50))
    test_index = []
    for i in range(10):
        rand_index = int(random.uniform(0, len(train_index)))  # 在[0, 50)生成一个随机实数
        test_index.append(train_index[rand_index])
        del (train_index[rand_index])
    train_matrix = []
    train_class = []
    for doc_index in train_index:
        train_matrix.append(words_to_vector(vocab_list, doc_list[doc_index]))
        train_class.append(class_list[doc_index])
    p1_vector, p0_vector, prob_1 = train_bayes(np.array(train_matrix), np.array(train_class))
    error_count = 0
    for doc_index in test_index:
        word_vector = words_to_vector(vocab_list, doc_list[doc_index])
        if classify_bayes(word_vector, p1_vector, p0_vector, prob_1) != class_list[doc_index]:
            error_count += 1
    print('the error rate is: %.4f' % (float(error_count) / len(test_index)))
    return float(error_count) / len(test_index)

其中的email里的两个文件夹的txt数据在读取的过程中会出现:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x92 in position 884: invalid start的错误
通过网络搜寻,找到如下解决方法:
首先,将txt文件用vim打开,输入:set, 查看fileencoding是否等于utf-8, 若不等于就会出现上面的错误,如fileencoding=latin1,这是由于文件编码的方式不对;
其次,按enter后,输入 :set fileencoding=utf-8,回车,esc,:wq, 保存退出,再次打开再查看就会看到fileencoding=utf-8了。
书中网址下载的邮件文件中,经本人踩坑,ham 6,23需要改, spam 17需要改,其他都ok。

2.9 垃圾分类错误率

if __name__ == '__main__':
  error_rate_list = []
    for i in range(10):
        error_rate_list.append(spam_test())
    print('average error rate is: ', np.mean(error_rate_list))

返回结果为:
the error rate is: 0.0000
the error rate is: 0.1000
the error rate is: 0.0000
the error rate is: 0.0000
the error rate is: 0.0000
the error rate is: 0.2000
the error rate is: 0.1000
the error rate is: 0.2000
the error rate is: 0.0000
the error rate is: 0.0000
average error rate is: 0.06

参考文献

  • Peter Harrington著,李锐,李鹏等译. 机器学习实战[M]. 人民邮电出版社.2018.1. p53-67
  • https://blog.csdn.net/wiki347552913/article/details/88060582

END


版权声明:本文为weixin_40356612原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。