朴素贝叶斯
朴素贝叶斯是贝叶斯决策理论的一部分,贝叶斯概率引入先验知识和逻辑推理来处理不确定命题。又可以称为“条件概率”(Conditional probability),与之相对的则是“频数概率”(frequency probability)。
强烈推荐看阮一峰大牛的这篇文章,看完基本贝叶斯就明白了。
我们把\(P(A|B)\)称为在B条件下A的概率,若只有A、B两个事件那么\(P(A|B)= {P(AB) \over P(B)} \) 。
全概率 公式:
$$P(B)=P(B|A)P(A) + P(B|\overline A)P(\overline A) $$
贝叶斯 公式:
$$P(A|B)={P(B|A) × P(A) \over P(B)}$$
对公式进行变形:
$$P(A|B)={P(A){P(B|A) \over P(B)}}$$
这里称P(A)为先验概率(Prior probability),即在B事件发生之前,我们对A事件概率的一个判断。P(A|B)称为后验概率(Posterior probability),即在B事件发生之后,我们对A事件概率的重新评估。P(B|A) / P(B) 称为可能性函数(Likelyhood),这是一个调整因子,使得预估概率更接近真实概率。
这里以贝叶斯界的”Hello World”为例,判断某种疾病患病概率问题:
已知某种疾病的发病率是0.001,即1000人中会有1个人得病。现有一种试剂可以检验患者是否得病,它的准确率是0.99,即在患者确实得病的情况下,它有99%的可能呈现阳性。它的误报率是5%,即在患者没有得病的情况下,它有5%的可能呈现阳性。现有一个病人的检验结果为阳性,请问他确实得病的可能性有多大?
我们假定阳性概率为P(B),发病的概率为P(A)=0.001,则没得病的概率\(P(\overline A)\)=0.999,确实得病且阳性概率为P(B|A)=0.99,没患病但阳性\(P(B|\overline A)\)=0.05,那么我们要求的问题就是P(A|B)了。
结合上面提到的全概率公式和贝叶斯公式,可以计算出他确实得病的概率仅为0.019,即“假阳性”。
如果把问题改成检验结果为阴性,问其患病的可能性。
我们假定阴性概率为P(B),发病的概率为P(A)=0.001,没得病的概率\(P(\overline A)\)=0.999,确实得病但阴性概率为P(B|A)=0.01,没患病且阴性\(P(B|\overline A)\)=0.95,那么检查为阴性但患病的概率就是:
$$P(A|B)={0.001×0.01 \over {0.01×0.001 + 0.95×0.999}} \approx 0.000011 $$
即便阴性也是有患病几率的,但概率十分低。
还有一个重要的公式叫做 联合概率 ,作用就是在已知多个事件发生的情况下,另一个事件发生的概率:
$$P ={ {P_1P_2…P_n } \over { {P_1P_2…P_n}+{(1-P_1)(1-P_2)…(1-P_n)} } } $$
接下来编写一个简陋的朴素贝叶斯分类器,这里还需要引用 条件独立性假设 ,即若各个条件互相独立,那么:
$$ P(w_1,w_2,…w_n|c_i) = P(w_1|c_i)P(w_2|c_i)…P(w_n|c_i) $$
现在假设有一句话,要判断这句话是消极的还是积极的,已知数据集如下:
1 | def load_dataset(): |
这里使用1代表积极,0代表消极,为了方便这里不涉及中文分词相关问题。
接下来创建数据集合,把所有句子中涉及到的词都放进一个列表中:
1 | def create_vocablist(dataset): |
要计算概率肯定涉及到文本向量化,这里又分为”词集模型”和”词袋模型”:
1 | def words2vec(vocablist, inputset): |
这两者的区别注释中已经给出,再下面将会看到具体结果。接下来创建分类器:
1 | def train_nb(train_matrix, train_category): |
其中,p_ab指先验概率,比如我们这里使用的例子里5个句子中有3个积极2个消极,那么P(消极)的先验概率就是0.4。而p1_vect
中则记录出现的单词的可能性函数值(参考上面可能性函数的解释)。简单说,假设一个单词在积极的句子中出现了10次,而表示积极的单词共有100个,那么一个积极的句子中出现该单词的概率就是0.1。
1 | def classify_nb(vec, p0_vect, p1_vect, p_class1): |
一个句子往往由多个单词组成,所以我们需要对其中出现的单词是积极还是消极进行求和,后面注意和该类别的概率对数相加。
下面来进行测试:
1 | list_oposts, list_class = load_dataset() |
输出为['我', '讨厌', '包子'] classify result: 消极
。
注意这里使用的是词袋模型,如果把句子改一改:
1 | ['讨厌', '包子'] classify result: 消极 |
第二句中居然变成了积极,因为有2个包子!这种情况下使用词集模型就不会出现这种错误,所以使用哪种模型因该看情况。