朴素贝叶斯

项目代码

朴素贝叶斯 (Bayes)

k-NN和决策树这类分类器的结果是非错即对(即明确给出数据预测类别),但有时我们希望分类器给出预测类别的概率估计值,这就引出了基于概率论的分类方法–朴素贝叶斯。(朴素的意思是在形式化过程中,只做最原始,最简单的假设)
在了解贝叶斯分类器之前,我们需要先了解什么是条件概率。

条件概率

条件概率:简单来说就是在A事件发生的条件下,B事件发生的概率,形式化描述为: p ( B ∣ A ) p(B|A) p(BA)
如果已知 p ( A ∣ B ) p(A|B) p(AB) p ( B ) p(B) p(B) p ( A ) p(A) p(A),则根据贝叶斯准则可知:
p ( B ∣ A ) p(B|A) p(BA) = p ( A ∣ B ) p ( B ) p ( A ) \frac{p(A|B)p(B)}{p(A)} p(A)p(AB)p(B)
那么怎么根据条件概率进行分类呢???

使用条件概率分类

如果用 p 1 ( c 1 ∣ ( x , y ) ) p_1(c_1|(x,y)) p1(c1(x,y))表示数据点 ( x , y ) (x,y) (x,y)属于类别 c 1 c_1 c1,用 p 2 ( c 2 ∣ ( x , y ) ) p_2(c_2|(x,y)) p2(c2(x,y))表示数据点 ( x , y ) (x,y) (x,y)属于类别 c 2 c_2 c2。则当
1) p 1 ( c 1 ∣ ( x , y ) ) > p 2 ( c 2 ∣ ( x , y ) ) p_1(c_1|(x,y)) > p_2(c_2|(x,y)) p1(c1(x,y))>p2(c2(x,y)) 时, ( x , y ) (x,y) (x,y)属于类别 c 1 c_1 c1;
2) p 1 ( c 1 ∣ ( x , y ) ) < p 2 ( c 2 ∣ ( x , y ) ) p_1(c_1|(x,y)) < p_2(c_2|(x,y)) p1(c1(x,y))<p2(c2(x,y)) 时, ( x , y ) (x,y) (x,y)属于类别 c 2 c_2 c2.
根据已知数据是可以计算出: p ( c i ) p(c_i) p(ci) p ( x , y ) p(x,y) p(x,y) p ( ( x , y ) ∣ c i ) p((x,y)|c_i) p((x,y)ci),因此:
p i ( c i ∣ ( x , y ) ) p_i(c_i|(x,y)) pi(ci(x,y)) = p ( ( x , y ) ∣ c i ) p ( c i ) p ( x , y ) \frac{p((x,y)|c_i)p(c_i)}{p(x,y)} p(x,y)p((x,y)ci)p(ci)

朴素贝叶斯的优缺点

优点:在数据较少的情况下仍然有效,可以处理多分类问题;
缺点:对于输入数据的准备方式较为敏感。
下面使用朴素贝叶斯进行文档分类。

词向量

计算机是看不懂我们所使用的单词或文字的,因此在进行文档分类之前,我们需要把文档中的单词或文字转换成计算机能够识别的数字形式,在此处需要将之处理成词向量的形式。
代码及结果如下(在utils.py模块中):

import numpy as np


def create_data():
    '''
    创建多个文档及其对应的标签
    :return: 文档内容,文档对应的标签
    '''
    docs_context = [['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']]
    docs_labels = [0, 1, 0, 1, 0, 1]  # 1 is abusive, 0 not
    return docs_context, docs_labels


def create_vocab_list(dataset):
    """
    创建词汇表
    :param dataset: 输入数据
    :return: 输入数据中不重复的词汇
    """
    vocab_set = []
    for doc in dataset:
        vocab_set = np.append(vocab_set, np.unique(doc))
    return np.unique(vocab_set)


def set_of_words_2_vec(vocabList, inputSet):
    '''
    将输入转换成词向量的形式
    :param vocabList: 词汇表
    :param inputSet: 输入文档
    :return: 输入文档对应的词向量形式
    '''
    re_vec = np.zeros((len(vocabList, )))
    for word in inputSet:
        if word in vocabList:
            re_vec[np.argwhere(np.array(vocabList) == word)] = 1
        else:
            print('the word: %s is not in Vocabulary' % word)
    return re_vec


if __name__ == "__main__":
    docs_context, docs_labels = create_data()
    vocabs = create_vocab_list(docs_context)
    print('多文档生成的词汇表:', vocabs)
    vec = set_of_words_2_vec(vocabs, docs_context[3])
    print('输入文档对应的词向量:', vec)
    # 多文档生成的词汇表: ['I' 'ate' 'buying' 'cute' 'dalmation' 'dog' 'flea' 'food' 'garbage' 'has'
    #             'help' 'him' 'how' 'is' 'licks' 'love' 'maybe' 'mr' 'my' 'not' 'park'
    #             'please' 'posting' 'problems' 'quit' 'so' 'steak' 'stop' 'stupid' 'take'
    #             'to' 'worthless']
    # 输入文档对应的词向量: [0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0.
    #              0. 0. 0. 1. 1. 0. 0. 1.]  # ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him']

从词向量计算概率

我们重写条件概率公式,将 ( x , y ) (x,y) (x,y)替换为 w w w w w w表示一个向量,则:
p i ( c i ∣ w ) p_i(c_i|w) pi(ciw) = p ( w ∣ c i ) p ( c i ) p ( w ) \frac{p(w|c_i)p(c_i)}{p(w)} p(w)p(wci)p(ci)
p ( c i ) p(c_i) p(ci)可以通过类别 i i i中文档数除以总的文档数计算;
计算 p ( w ∣ c i ) p(w|c_i) p(wci)需要用到朴素贝叶斯假设。假设将 w w w展开为一个一个独立特征,即所有词相互独立,也称条件独立性假设,则:
p ( w ∣ c i ) = p ( w 0 , w 1 , w 2 . . . w n ∣ c i ) = p ( w 0 ∣ c i ) p ( w 1 ∣ c i ) p ( w 2 ∣ c i ) . . . p ( w n ∣ c i ) p(w|c_i)= p(w_0,w_1,w_2...w_n|c_i)=p(w_0|c_i)p(w_1|c_i)p(w_2|c_i)...p(w_n|c_i) p(wci)=p(w0,w1,w2...wnci)=p(w0ci)p(w1ci)p(w2ci)...p(wnci)
使用朴素贝叶斯进行文档分类的伪代码如下:

"""
Bayes算法的伪代码
1. 计算每个类别中的文档数目
2. 训练每篇文档:
3. for 文档类别:
4.     对每个类别:
5.        如果词条出现在文档中----->增加该词的计数值
6.        增加所有词条的计数值
7. 对每个类别:
8.     对每个词条:
9.         该词条的数目/总词条数目=条件概率
10. 返回每个类别的条件概率
"""

代码实现如下(在bayes.py模块中):

def cond_probability(train_matrix, train_category):
    '''
    计算条件概率, 此方法可以进行多分类
    :param train_matrix: 所有文档词向量组成的祖矩阵
    :param train_category: 文档类别
    :return: 词向量中每个元素的概率,每种类别的占比
    '''
    num_train_docs = len(train_matrix)  # 统计样本数量
    num_words = len(train_matrix[0])  # 统计词汇量的大小
    train_category_ = train_category[:]  # 复制 train_category
    num_category = len(np.unique(train_category_))  # 统计类别数量

    pAbusive = np.zeros((num_category, 1))
    for category, count in collections.Counter(train_category_).most_common():  # 计算每个类别的占比
        pAbusive[category] = count / num_train_docs

    p_num = np.ones((num_category, num_words))  # 初始化为1: 防止某一个概率为0,导致相乘结果为0
    p_demon = np.ones((num_category, 1)) * 2

    for i in range(num_train_docs):
        p_num[train_category[i]] += train_matrix[i]
        p_demon[train_category[i]] += np.sum(train_matrix[i])

    p_vec = np.log(p_num / p_demon) # 取对数:防止过多较小数相乘,导致结果数值下溢出

    del train_category_
    return p_vec, pAbusive

求出来条件概率后进行预测(在bayes.py模块中):

def classifyNB(test_data, p_vec, p_class):
    '''
    对输入文档进行预测
    :param test_data: 输入测试文档
    :param p_vec:  词向量中每个元素的概率
    :param p_class: 每种类别的占比
    :return:
    '''
    p = np.reshape(np.sum(test_data * p_vec, axis=1), (2, 1)) + np.log(p_class)
    return np.argmax(p)

测试代码:

from bayes import *
from utils import *

if __name__ == "__main__":
    docs_context, docs_labels = create_data()
    vocabs = create_vocab_list(docs_context)
    train_mat = []
    for doc in docs_context:
        train_mat.append(set_of_words_2_vec(vocabs, doc))
    p_vec, pAbusive = cond_probability(train_mat, docs_labels)
    # print(p_vec)
    # print(pAbusive)
    # exit()
    test_entry = ['love', 'my', 'dalmation']
    thisDoc = set_of_words_2_vec(vocabs, test_entry)
    print(test_entry, 'classified as: ', classifyNB(thisDoc, p_vec, pAbusive))

    test_entry = ['stupid', 'garbage']
    thisDoc = set_of_words_2_vec(vocabs, test_entry)
    print(test_entry, 'classified as: ', classifyNB(thisDoc, p_vec, pAbusive))
    # ['love', 'my', 'dalmation'] classified as:  0
    # ['stupid', 'garbage'] classified as:  1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值