基于概率论的分类方法:朴素贝叶斯

目录

基于贝叶斯决策理论的分类方法

条件概率

使用条件概率来分类

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

使用python进行文本分类

准备数据:从文本中构建词向量

训练算法:从词向量计算概率

测试算法:根据情况修改分类器

文档词袋模型


概率论是许多机器学习算法的基础,深刻理解这一主题就显得十分重要。

这所以称之为朴素,是因为整个刑事化过程中只做最原始、最简单的假设。

举个例子说明朴素:

假设bacon出现在unhealthy后面与出现在delicious后面的概率相同。当然,我们知道这种假设并不正确,bacon经常出现在delicious后面但是很少出现在unhealthy后面,这种假设正是“朴素”一次的含义。

基于贝叶斯决策理论的分类方法

朴素贝叶斯

优点:在数据较少的情况下仍然有效,可以处理多类别问题。

缺点:对于摄入数据的准备方式较为敏感。

使用数据类型:标称型数据。

 我们现在用p_1(x,y)表示数据点(x,y)属于类别1,p_2(x,y)表示数据点(x,y)属于类别2,可以用下面的规则来判断它们的类别:

  • 如果p_1(x,y)>p_2(x,y),则类别为1
  • 如果p_2(x,y)>p_1(x,y),则类别为2

也就是说,我们会选择高概率对应的类别,这就是贝叶斯决策理论的核心思想。

条件概率

计算条件概率的方法称为贝叶斯准则。贝叶斯准则告诉我们如何交换条件概率的条件与结果,即如果已知p(x|c),要求p(c|x),可以使用下面的计算方法:

p(c|x)=\frac{p(x|c)p(c)}{p(x)}

使用条件概率来分类

如果特征有两个,应用贝叶斯准则得到:

p(c_i|x,y)=\frac{p(x,y|c_i)p(c_i)}{p(x,y)}

使用这些定义,可以定义贝叶斯分类准则为:

  • 如果p(c_1|x,y)>p(c_2|x,y),则类别为c_1
  • 如果p(c_2|x,y)>p(c_1|x,y),则类别为c_2

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

机器学习的一个重要应用就是文档的自动分类。我们可以观察文档中出现的词,并把每个词的出现或者不出现作为一个特征,这样的到的特征数目就会跟词汇表中的词目一样多。

朴素贝叶斯的一般过程

  1. 收集数据:可以使用任何方法,此处使用RSS源。
  2. 准备数据:需要数值型或布尔型数据。
  3. 分析数据:有大量特征时,绘制特征作用不大,此时使用直方图效果更好。
  4. 训练算法:计算不同的独立特征的条件概率。
  5. 测试算法:计算错误率。
  6. 使用算法:一个常见的朴素贝叶斯应用是文档分类。可以在任意的分类场景中使用朴素贝叶斯分类器,不一定非要是文本。

 朴素贝叶斯分类器有两种假设:

一是特征之间相互独立;

二是每个特征同等重要。

使用python进行文本分类

要从文本中获取特征,需要先拆分文本。这里的特征是来自文本的词条(token),一个词条是字符的任意组合。然后把么一个文本片段表示为一个词条向量,其中值为1表示词条出现在文档中,0表示词条未出现。

准备数据:从文本中构建词向量

def load_data_set():
    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代表侮辱性文字,0代表正常言论
    return posting_list, class_vec


def create_vocab_list(data_set):
    vocab_set = set([])
    for document in data_set:
        vocab_set = vocab_set | set(document)
    return list(vocab_set)


def set_of_word2vec(vocab_list, input_set):
    return_vec = [0] * len(vocab_list)
    for word in input_set:
        if word in vocab_list:
            return_vec[vocab_list.index(word)] = 1
        else:
            print("the word: %s is not in the vocabulary" % word)
    return return_vec


if __name__ == '__main__':
    post_list, label_list = load_data_set()
    vocab_list = create_vocab_list(post_list)
    print(set_of_word2vec(vocab_list, post_list[0]))

结果:

[0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0]

训练算法:从词向量计算概率

训练朴素贝叶斯的伪代码如下:

  • 计算每个类别中的文档数目
  • 对每篇训练文档:
    • 对每个类别:
      • 如果词条出现在文档中 -> 增加该词条的计数值
      • 增加所有词条的计数值
    • 对每个类别:
      • 对每个词条:
        • 将该词条的数目处以总词条数目得到条件概率
    • 返回每个类别的条件概率

 

def train_naive_bayes(train_matrix, train_category):
    train_docs_num = len(train_matrix)
    words_num = len(train_matrix[0])
    p_abusive = sum(train_category)/float(train_docs_num)
    p0_num = np.zeros(words_num)
    p1_num = np.zeros(words_num)
    p0_sum = 0.0
    p1_sum = 0.0
    for i in range(train_docs_num):
        if train_category[i] == 1:
            p1_num += train_matrix[i]
            p1_sum += sum(train_matrix[i])
        else:
            p0_num += train_matrix[i]
            p0_sum += sum(train_matrix[i])
    p0_vec = p0_num/p0_sum
    p1_vec = p1_num/p1_sum
    return p0_vec, p1_vec, p_abusive


post_list, label_list = load_data_set()
vocab_list = create_vocab_list(post_list)
print(set_of_word2vec(vocab_list, post_list[0]))
train_mat = []
for post_doc in post_list:
    train_mat.append(set_of_word2vec(vocab_list, post_doc))
p0, p1, p_abusive = train_naive_bayes(train_mat, label_list)
print("P0: ", p0)
print("P1: ", p1)
print("P_abusive:", p_abusive)

结果:

[1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1]
P0:  [0.04166667 0.04166667 0.04166667 0.         0.04166667 0.
 0.125      0.04166667 0.         0.         0.04166667 0.04166667
 0.         0.04166667 0.04166667 0.         0.04166667 0.
 0.         0.04166667 0.         0.         0.08333333 0.04166667
 0.04166667 0.04166667 0.04166667 0.04166667 0.04166667 0.04166667
 0.         0.04166667]
P1:  [0.         0.         0.         0.10526316 0.         0.05263158
 0.         0.         0.05263158 0.05263158 0.         0.
 0.15789474 0.         0.05263158 0.05263158 0.10526316 0.05263158
 0.05263158 0.         0.05263158 0.05263158 0.05263158 0.
 0.         0.         0.05263158 0.         0.         0.
 0.05263158 0.        ]
P_abusive: 0.5

其中,p0_num表示标签为0的词条出现在文档中的次数,p0_sum表示标签为0的词条的总数目

p1_num表示标签为1的词条出现在文档中的次数,p1_sum表示标签为1的词条的总数目

p_{0}=\frac{p_{num}^{\{0\}}}{p_{sum}^{\{0\}}} 表示标签为0的词条下每个词出现的概率——p(\bold{w}|c_0)

p_{1}=\frac{p_{num}^{\{1\}}}{p_{sum}^{\{1\}}} 表示标签为1(含有侮辱性词汇)的词条下每个词出现的概率——p(\bold{w}|c_1)

p_{abusive}表示的是词条标签为1的概率——p(c_1)

 

在使用该函数进行分类之前,我们还需要解决函数中的一些缺陷。

测试算法:根据情况修改分类器

利用贝叶斯分类器对文档进行分类时,要计算索格概率的乘积以获得文档属于某个类别的概率,即计算p(w_0|1)p(w_1|1)p(w_2|1)。如果其中一个概率值为0,那么最后的乘积也是0。为降低这种影响,可以将所有词出现的次数初始化为1,并将分母初始化为2。

另一个遇到的问题是下溢出,这是由于太多很小的数相乘造成的。在计算p(w_0|c_i)p(w_1|c_i)p(w_2|c_i)\cdots p(w_n|c_i)时,由于大部分因子都非常小,所以程序会下溢出或者得到不正确的答案。一种解决办法是对乘积取自然对数,即

\ln{p(w_0|c_i)p(w_1|c_i)p(w_2|c_i)\cdots p(w_n|c_i)}=\ln{p(w_0|c_i)}+\ln{p(w_1|c_i)}+\ln{p(w_2|c_i)}+\cdots+\ln{p(w_n|c_i)}

这样,train_naive_bayse()函数修改为:

def train_naive_bayes(train_matrix, train_category):
    train_docs_num = len(train_matrix)
    words_num = len(train_matrix[0])
    p_abusive = sum(train_category)/float(train_docs_num)
    p0_num = np.ones(words_num)
    p1_num = np.ones(words_num)
    p0_sum = 2.0
    p1_sum = 2.0
    for i in range(train_docs_num):
        if train_category[i] == 1:
            p1_num += train_matrix[i]
            p1_sum += sum(train_matrix[i])
        else:
            p0_num += train_matrix[i]
            p0_sum += sum(train_matrix[i])
    p0_vec = np.log(p0_num/p0_sum)
    p1_vec = np.log(p1_num/p1_sum)
    return p0_vec, p1_vec, p_abusive

测试朴素贝叶斯分类器分类结果:

def classify_naive_bayes(vec2classify, p0_vec, p1_vec, p_class1):
    p1 = np.sum(vec2classify * p1_vec) + np.log(p_class1)
    p0 = np.sum(vec2classify * p0_vec) + np.log(1 - p_class1)
    print("p1:", p1)
    print("p0:", p0)
    if p1 > p0:
        return 1
    else:
        return 0


def test_naive_bayes():
    post_list, label_list = load_data_set()
    vocab_list = create_vocab_list(post_list)
    train_mat = []
    for post_doc in post_list:
        train_mat.append(set_of_word2vec(vocab_list, post_doc))
    p0_v, p1_v, p_ab = train_naive_bayes(train_mat, label_list)
    test_vocab = ['love', 'my', 'dalmation']
    test_doc = set_of_word2vec(vocab_list, test_vocab)
    test_class = classify_naive_bayes(test_doc, p0_v, p1_v, p_ab)
    print(test_vocab, "is classified as class", test_class)


if __name__ == '__main__':
    test_naive_bayes()

输出:

p1: -9.826714493730215
p0: -7.694848072384611
['love', 'my', 'dalmation'] is classified as class 0

文档词袋模型

上面将每个词是否出现作为一个特征(出现,对应词向量置1;不出现,词向量为0),这种模型被描述为词集模型。

如果一个词在文档中出现不只一次,这可能意味着包含该次出现在文档中所不能表达的信息,这种每个词每出现一次,对应的词向量加1的模型称为词袋模型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值