朴素贝叶斯分类器-文档分类

朴素贝叶斯理论概述

朴素贝叶斯(navie bayes)是贝叶斯决策理论的一部分,只考虑最简单的假设,用 Python 将文本切分为词向量,然后利用词向量对文档分类。

  • 优点:在数据较少的情况下仍然有效,可以处理多类别问题。
  • 缺点:对于输入数据的准备方式较为敏感。
  • 适用数据类型:标称型数据。

k-近邻算法决策树 相比,都属于适用于标称型数据的分类器。

考虑下面的情形:
在这里插入图片描述
有一个数据集,它由两类数据组成,我们现在用 p1(x,y) 表示数据点(x,y)属于类别1的概率,用 p2(x,y) 表示数据点(x,y)属于类别2的概率。

那么对于一个新数据点(x,y),显然

  • 如果 p1(x,y) > p2(x,y) ,那么类别为1。
  • 如果 p2(x,y) > p1(x,y) ,那么类别为2。
    也就是说,我们会选择高概率对应的类别。这就是贝叶斯决策理论的核心思想。

如果不用贝叶斯决策理论:

  • 使用第1章的 kNN,进行1000次距离计算;
  • 使用第2章的决策树,分别沿x轴、y轴划分数据;
  1. kNN算法效率会非常低
  2. 决策树在划分数据时会遇到困难,选出最优分类的时候不能很好解决。倘若不止两个轴,那么计算量更是成倍增加。

条件概率

贝叶斯准则:


在这里插入图片描述
其中 x是一个向量,对于这个例子


在这里插入图片描述
比较 i 取 (0,1)的时候的大小来判断。结合公式,判断分子 p ( x , y ∣ c i ) p(x,y|c_i) p(x,yci) p ( c i ) p(c_i) p(ci)即可。

p ( c i ) p(c_i) p(ci) 即为 c i c_i ci除以总数。
p ( x , y ∣ c i ) p(x,y|c_i) p(x,yci) 即在 c i c_i ci条件下统计(x,y)出现的概率。

用朴素贝叶斯进行文档分类

后面的例子都可以用文档doc的模型,整个文档如电子邮件是一个实例,文档中的某些元素构成特征。我们可以统计文档中出现的词word,并用它出现或不出现,出现次数作为特征。这样就可以用一个长度统一,内容是特征的向量来描述文档。

朴素贝叶斯中朴素naive的含义是每个特征互相独立,所以根据乘法原理,总概率为各特征相乘。

Python中为了防止下溢出通常计算log(prob),把相乘操作转换为相加。

文本分类代码

一般步骤:


1.构建词向量
2.构造包含词向量的 train_matrix
3.train_NB() 计算出词分量的概率
4.构造inputset的词分量
5.调用classify_NB,用 词分量概率和 inputset的词分量 判断结果
from numpy import *

# 创建数据集 class_vec相等于 label
def load_dataset():
    posting_list = [['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']]
    class_vec = [0, 1, 0, 1, 0, 1]  # 1 is abusive, 0 not
    return posting_list, class_vec

# 创建包含所有word的list 中间变量
def create_vocab_list(posting_list):
    vocab_set = set([])
    for i in posting_list:
        vocab_set = vocab_set | set(i)
    return list(vocab_set)

# 创建向量
# wordset to vec
def docs_2_vec(vocab_list, docs):
    vec = [0] * len(vocab_list)
    for i in docs:
        if i in vocab_list:
            vec[vocab_list.index(i)] += 1 # 出现则记为1
        else:
            print('the word: {} is not in my vocabulary!\n'.format(i))
    return vec

# 计算概率
# abusive : 侮辱性
def train_NB0(train_matrix, train_category):
    num_docs = len(train_matrix)
    num_words = len(train_matrix[0])
    prob_abusive = sum(train_category) / float(num_docs)
    # init the num ,
    # 分子初始化为1
    num_0 = ones(num_words)
    num_1 = ones(num_words)
    # 分母 denom=2
    denom_0 = 2.0
    denom_1 = 2.0
    for i in range(num_docs):
        # 计算不同分类下的概率
        if train_category[i] == 1:
            denom_1 += sum(train_matrix[i])
            num_1 += train_matrix[i]
        else:
            denom_0 += sum(train_matrix[i])
            num_0 += train_matrix[i]
    prob_1_vec = num_1 / denom_1  # add log()
    prob_0_vec = num_0 / denom_0
    return prob_1_vec, prob_0_vec, prob_abusive


def classify_NB(input_vec, prob_1_vec, prob_0_vec, prob_abusive):
    # 相乘 取对数
    prob_1 = sum(input_vec * prob_1_vec) + log(prob_abusive)
    prob_0 = sum(input_vec * prob_0_vec) + log(1.0 - prob_abusive)
    if prob_1 > prob_0:
        return 1
    else:
        return 0


def test_NB():
    post_list, class_vec = load_dataset()
    vocab_list = create_vocab_list(post_list)
    train_matrix = []
    for docs in post_list:
        train_matrix.append(docs_2_vec(vocab_list, docs))
    prob_1_vec, prob_0_vec, prob_abusive = train_NB0(array(train_matrix), class_vec)
    print(prob_1_vec)
    print(prob_0_vec)
    # 2 test_docs
    test_docs_1 = ['love', 'my', 'dalmation']
    test_docs_2 = ['stupid', 'garbage']
    test_1_vec = docs_2_vec(vocab_list, test_docs_1)
    test_2_vec = docs_2_vec(vocab_list, test_docs_2)
    ans_1 = classify_NB(test_1_vec, prob_1_vec, prob_0_vec, prob_abusive)
    ans_2 = classify_NB(test_2_vec, prob_1_vec, prob_0_vec, prob_abusive)
    print('test_docs_1 is {}\n', 'negative' if ans_1 else 'positive')
    print('test_docs_2 is {}\n', 'negative' if ans_2 else 'positive')


if __name__ == '__main__':
    test_NB()

文档词袋模型

set_of_words为文档词集模型

def docs_2_vec(vocab_list, docs):
    vec = [0] * len(vocab_list)
    for i in docs:
        if i in vocab_list:
            vec[vocab_list.index(i)] = 1# 代码中已改为 +=1
        else:
            print('the word: {} is not in my vocabulary!\n'.format(i))
    return vec
def bagofwords_2_vec(vocab_list, docs):
    ...
        vec[vocab_list.index(i)] += 1
    ...

词袋模型的意义是特征可能多次出现,意味着它包含着是否出现在外当中以外的更多意义。

实例:朴素贝叶斯过滤垃圾邮件

和样例相比多了两个过程

  • 准备数据:切分文本
  • 测试算法(随机采样数据)
from NaiveBayes import *


def bagofwords_2_vec(vocab_list, docs):
    vec = [0] * len(vocab_list)
    for word in docs:
        if word in vocab_list:
            vec[vocab_list.index(word)] += 1
        else:
            print('word {} is not in vocab_list!\n'.format(word))
    return vec


def test_parse(bigstring):
    import re
    tokens_list = re.split(r'\W*', bigstring)
    return [token.lower() for token in tokens_list if len(token) > 2]


# spam : 垃圾邮件
# ham : not a spam && disired e-mail
def spam_test():
    doc_list = []
    class_list = []
    for i in range(1, 26):
        file=open('email/spam/{}.txt'.format(i),'r')
        word_list = test_parse(file.read())
        doc_list.append(word_list)
        class_list.append(1)
        file = open('email/ham/{}.txt'.format(i), 'r')
        word_list = test_parse(file.read())
        doc_list.append(word_list)
        class_list.append(0)
    vocab_list = create_vocab_list(doc_list)
    # select 10 set in vocab as test set
    trainset = list(range(50))
    testset = [] # include doc_index
    for i in range(10):
        rand_index = int(random.uniform(0, len(trainset)))
        testset.append(rand_index)
        del (trainset[rand_index])
    train_matrix = []
    train_class = []
    for doc_index in trainset:
        train_matrix.append(bagofwords_2_vec(vocab_list, doc_list[doc_index]))
        train_class.append(class_list[doc_index])
    prob_1_vec, prob_0_vec, prob_abusive = train_NB0(train_matrix, train_class)

    # test
    error_count = 0.
    for doc_index in testset:
        test_vec = bagofwords_2_vec(vocab_list, doc_list[doc_index])
        ans = classify_NB(array(test_vec), prob_1_vec, prob_0_vec, prob_abusive)
        if ans != class_list[doc_index]:
            error_count += 1
            print('classification error {}'.format(doc_list[doc_index]))
    print('error rate is {}!\n'.format(float(error_count) / len(testset)))


if __name__ == '__main__':
    spam_test()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值