朴素贝叶斯算法

一、朴素贝叶斯分类算法简述

  1、贝叶斯公式和全概率公式

  举一个概率论中的例子。设某工厂有甲、乙、丙三个车间生产同一种产品,已知各车间的产量分别占全厂产量的25%、35%、40%,而且各车间的次品率依次为5%、4%、2%。现问:

  (1)生产的产品是次品的概率是多少?

  (2)如果是次品,该次品是甲工厂生产的概率是多少?

  显然:

  设一个产品属于甲、乙、丙工厂的概率分别为P(A) = 0.25, P(B) = 0.35, P(C) = 0.4。如果用no 表示次品,则有p(no|A) = 0.05, p(no|B) = 0.04, p(no|C) = 0.02。

  那么对于第一问,可以用全概率公式计算:

  p(no) = p(no|A)*p(A) + p(no|B)*p(B) + p(no|C)*p(C) = 0.25*0.05 + 0.35*0.04 + 0.4*0.02 = 0.0345

  对于第二问,则计算p(no)中出现p(no|A)*p(A)的概率即可:

  p(A|no) = p(no|A)*p(A) / p(no) = 0.3623

  2、朴素贝叶斯之核

  贝叶斯分类算法的一个核心思想是:如果知道某些特征,怎么可以确定它属于哪个类别?

  观察贝叶斯公式:

      $$P(Y|X) = \frac{P(X|Y)P(Y)}{P(X)}$$

  我们可以借用贝叶斯公式,将贝叶斯分类器表达为:

      $$ P("属于某类"|"具有某些特征") = \frac{P("具有某些特征"|"属于某类") P("属于某类")}{P("具有某特征")} $$

  对于上面的一些概率,作如下解释:

    1.P("具有某些特征"|"属于某类"):在已知某样本"属于某类"的条件下,该样本"具有某特征"的概率。对于已有的训练集,这个条件是已知的。

    2.P("属于某类"):在未知某样本"具有某特征"的条件下,该样本"属于某类"的概率。对于已有的训练集,这个条件也是已知的。比如100个样本,有60个是a,有40个是b。那么在不知道新样本的具体数值时,我们认为它属于a的概率是60%,属于b的概率是40%。它叫作先验概率。

    3.P("具有某特征"):在未知某样本"属于某类"的条件下,该样本"具有某特征"的概率。对于一个给定的样本,我们认为它具有某特征的概率恒为1,因为它的特征已完全给定。

    4.P("属于某类"|"具有某特征"):在已知某样本"具有某特征"的条件下,该样本"属于某类"的概率。它叫作后验概率。这是我们想要得到的结果。

  由此可见,对于P("属于某类"|"具有某特征")的计算,只需要计算P("具有某些特征"|"属于某类") P("属于某类")即可。而P("属于某类")在给定带标签的数据集时可以很简便的计算得到,所以计算P("具有某些特征"|"属于某类")才是朴素贝叶斯分类器的核心。

  值得注意的是:全概率公式要求条件概率两两独立。为了满足其要求,朴素贝叶斯分类器在套用贝叶斯公式时,也假定所有的特征两两独立。尽管在现实中这是不可能的,但在某些应用场景中,朴素贝叶斯的分类效果仍然令人惊叹。

  3、朴素贝叶斯之刃

  朴素贝叶斯分类器通常出现在文本处理中。提到文本处理就应想到它的一系列流程:获取文档、切词(用户字典)、清洗(包括停用词、特殊字符、标点符号等)、降维(稀疏矩阵)、构建向量空间模型(TF-IDF)、建模(LDA等), 或者构建word2Vec、建模(RNN、LSTM)。

  朴素贝叶斯既然认为词与词之间的是相互独立的,显然要立足于向量空间模型(Vector space model)。

  向量空间模型做法如下:

    将所有语句中的词生成唯一值(bag of words)序列,作为特征向量。每条语句(文本)出现词的频数作为行向量。从而构成向量空间模型。

  举个例子:

import numpy as np
import pandas as pd
lis = [
    ["dog", "cat", "fish"],
    ["lion", "tiger"],
    ["cat", "fish"],
    ["dog"],
]
bags = list(set([word for row in lis for word in row]))
vsm = np.zeros([len(lis), len(bags)])
for i, row in enumerate(lis):
    for word in row:
        vsm[i, bags.index(word)] += 1
vsm = pd.DataFrame(vsm, columns=bags)
print(vsm)

  打印结果为:

  dog tiger fish lion cat
0 1.0 0.0 1.0 0.0 1.0
1 0.0 1.0 0.0 1.0 0.0
2 0.0 0.0 1.0 0.0 1.0
3 1.0 0.0 0.0 0.0 0.0

  TF-IDF在向量空间模型的基础上,对每个词的权重做了一些处理。它认为,如果一个词在该条句子(对应上表中的一行)中出现的频率非常高,并且在其它句子中出现的频率又非常低,那么这个词代表的信息量就越大,其权重值也越大。TF(词频)用于计算一个词在该条句子中的频率,IDF(反文档频率)用于计算一个词在每个句子中出现的频率。

  例如:

    第0行dog的TF词频为:$\frac{[0, dog]}{[0, dog] + [0, fish] + [0, cat]} = 0.33$

    第0行dog的IDF反文档频率为:$\log \frac{数据集长度}{[0, dog] + [3, dog]} = \log(4/2) = 0.69$

    第0行dog的TF-IDF权重值为:$ 0.33 * 0.69 = 0.228 $

  向量空间模型中所有元素的TF-IDF权重值构成的矩阵,称为TF-IDF权重矩阵。TF-IDF权重矩阵为p("属于某类"|"具有某些特征")的计算提供了基础。

  4、朴素贝叶斯算法的流程

    计算每个类别中的文档数目和其频率  # 实际计算P("属于某类”)

    对每篇训练文档:
          对每个类别:
              如果词条出现在文档中,增加该词条的计数值
              增加所有词条的计数值
          对每个类别:
              对每个词条:
                  将该词条的数目除以总词条数目得到条件概率
         返回每个类别的条件概率   # 实际计算P("具有某些特征"|"属于某类")

二、python3实现朴素贝叶斯

  1、python3实现朴素贝叶斯

  创建LoadDataSet类,用于生成数据集;创建NavieBayes类,用于实现朴素贝叶斯。

    NavieBayes:

    train:训练数据集

    predict:测试数据集

    _calc_wordfreq:

import numpy as np
import pandas as pd

class LoadDataSet(object):
    def get_dataSet(self):
        """lis是一行行文字切词后的文档集合,内容是斑点犬评论"""
        lis = [
            ["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"],
        ]
        vec= [0, 1, 0, 1, 0, 1]  # 1代表侮辱性文字,0代表正常言论;对应lis的6行数据
        return lis, vec

class NavieBayes(object):
    def __init__(self):
        self.Pcates = {}
        self.vocabulary  = None
        self.tf = None
    def train(self, trainSet, classVec):
        """训练集计算"""
        self.Pcates = {
            label:{
                "prob": classVec.count(label)/len(classVec),  # 记录P("属于某类")
                "tdm": None                                   # 记录p("具有某特征"|"属于某类")
            } for label in set(classVec)
}  # 计算每个类别的先验概率,保存成字典格式
        self.vocabulary = list(set([word for doc in trainSet for word in doc]))  # 生成词袋
        self.tf = self._tf_idf(trainSet)
        self._bulid_tdm(trainSet, classVec)

    def _tf_idf(self, trainSet):
        """生成tf和idf"""
        # 心中要有tf-idf矩阵
        vocLength = len(self.vocabulary)
        docLength = len(trainSet)
        idf = np.zeros([1, vocLength])  # 因为vocabulary是特征向量,所以写1 x N的向量,用以表示一个文档向量中葛格慈的频率
        tf = np.zeros([docLength, vocLength])  # tf矩阵:每个词的词频矩阵
        for i, doc in enumerate(trainSet):
            for word in doc:   # 统计每一行中的每个词在该行中出现的次数
                tf[i, self.vocabulary.index(word)] += 1  # 遍历每个词,计算其出现的次数并写到tf矩阵对应的位置
            tf[i] = tf[i] / len(trainSet[i])
            # 这一行的tf除以该行文件中的词总数(实际上就是row长度)以消除长短句的影响
            for singleword in set(doc):
                idf[0, self.vocabulary.index(singleword)] += 1  # 统计每个文档里的词在所有文档里出现的次数
            idf = np.log(len(trainSet) / (idf + 1))   # +1是为了防止0除
        return np.multiply(tf, idf)

    def _bulid_tdm(self, trainSet, classVec):
        """计算每个类别下每个词出现的概率"""
        tf_labels = np.c_[self.tf, labels]  # 在权重矩阵后面增加一列labels
        for label in self.Pcates.keys():
            label_tf_group = tf_labels[tf_labels[:, -1] == label][:, :-1]  # 获取label类对应的tf子矩阵
            label_tf = np.sum(label_tf_group, axis=0)/np.sum(label_tf_group)  # 行累加除以总值
            self.Pcates[label]["tdm"] = label_tf  # p("具有某特征"|"属于某类")

    def predict(self, test_wordList):
        """测试分类数据"""
        # 首先根据word_list生成词向量
        test_wordArray = np.zeros([1, len(self.vocabulary)])
        for word in test_wordList:
            test_wordArray[0, self.vocabulary.index(word)] += 1
        # 其次计算p("具有某特征"|"属于某类") * p("属于某类")
        # 不计算p("具有某特征")是因为假定对于每个测试的样本,它们具有的特征是完全随机的,都是一样的概率。
        pred_prob = 0
        pred_label = None
        for label, val in self.Pcates.items():
            test_prob = np.sum(test_wordArray * val["tdm"] * val["prob"])
            if test_prob > pred_prob:
                pred_prob = test_prob
                pred_label = label
        return {"predict_probability": round(pred_prob,4), "predict_label": pred_label}

  来一段测试代码:

load = LoadDataSet()
trainSet, labels = load.get_dataSet()
bayes = NavieBayes()
bayes.train(trainSet, labels)
bayes.predict(trainSet[0])

  2、sikit-learn实现朴素贝叶斯

  这里要用到sklearn.feature_extraction.text中的TfidfTransformer和CountVectorizer。

from sklearn import naive_bayes
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer

trainSet, labels = LoadDataSet().get_dataSet()
trainSet = [" ".join(row) for row in trainSet]

vectorizer = CountVectorizer()     # 用拼接的句子输入,它要生成svm,不接受长短不一的列表
transformer = TfidfTransformer()   # tf-idf权重矩阵

vsm = vectorizer.fit_transform(trainSet)  # 训练vsm模型
# print(vsm.toarray())
# 更多方法请参阅 http://scikit-learn.org/stable/modules/feature_extraction.html#common-vectorizer-usage
tfidf = transformer.fit_transform(svm)    # 转换成tf-idf模型

# 生成测试用的数据
test = vectorizer.transform([trainSet[0]])
test = transformer.transform(test)

# 这里用混合贝叶斯模型;有兴趣的可以看伯努利模型、高斯模型
bys = naive_bayes.MultinomialNB()
bys.fit(tfidf, labels)

testData = trainSet[0]
bys.predict(test)

  

原文地址:https://www.cnblogs.com/kuaizifeng/p/9117916.html

时间: 2024-10-13 10:02:16

朴素贝叶斯算法的相关文章

挖掘算法(1)朴素贝叶斯算法

原文:http://www.blogchong.com/post/NaiveBayes.html 1 文档说明 该文档为朴素贝叶斯算法的介绍和分析文档,并且结合应用实例进行了详细的讲解. 其实朴素贝叶斯的概念以及流程都被写烂了,之所以写这些是方便做个整理,记录备忘.而实例部分进行了详细的描述,网络上该实例比较简单,没有过程. 至于最后部分,则是对朴素贝叶斯的一个扩展了,当然只是简单的描述了一下过程,其中涉及到的中文分词以及TFIDF算法,有时间再具体补上. 2 算法介绍 2.1 贝叶斯定理 (1

统计学习方法 -> 朴素贝叶斯算法

需要知道的是在什么时候可以用朴素贝叶斯算法:需要保证特征条件独立. 主要过程是学习输入和输出的联合概率分布. 预测的时候,就可以根据输入获得对打后验概率对应的输出y. 先验概率:已知输出,求输入.后验概率相反. 简单来说朴素贝叶斯算法,就是在对样本进行学习之后,到了需要做决策的时候,给定x,给出最大概率的y.这个本质上就是一个典型的后验概率模型.不过在该模型的算法推到上,还用到了先验概率的计算.但注意:最终朴素贝叶斯就是一种后验概率模型求P(y|x). 后验概率模型有一个好处,相当于期望风险最小

朴素贝叶斯算法及实现

1.朴素贝叶斯算法介绍 一个待分类项x=(a,b,c...),判断x属于y1,y2,y3...类别中的哪一类. 贝叶斯公式: 算法定义如下: (1).设x={a1, a2, a3, ...}为一个待分类项,而a1, a2, a3...分别为x的特征 (2).有类别集合C={y1, y2,  y3,  ..} (3).计算p(y1|x), p(y2|x), p(y3|x), .... (4).如果p(y(k)|x)=max{p(y1|x), p(y2|x), p(y3|x), ....},则x属于

朴素贝叶斯算法资料整理和PHP 实现版本

朴素贝叶斯算法简洁 http://blog.csdn.net/xlinsist/article/details/51236454 引言 先前曾经看了一篇文章,一个老外程序员写了一些很牛的Shell脚本,包括晚下班自动给老婆发短信啊,自动冲Coffee啊,自动扫描一个DBA发来的邮件啊, 等等.于是我也想用自己所学来做一点有趣的事情.我的想法如下: 首先我写个scrapy脚本来抓取某个网站上的笑话 之后写个Shell脚本每天早上6点自动抓取最新的笑话 然后用朴素贝叶斯模型来判断当前的笑话是否属于成

C#编程实现朴素贝叶斯算法下的情感分析

C#编程实现 这篇文章做了什么 朴素贝叶斯算法是机器学习中非常重要的分类算法,用途十分广泛,如垃圾邮件处理等.而情感分析(Sentiment Analysis)是自然语言处理(Natural Language Progressing)中的重要问题,用以对文本进行正负面的判断,以及情感度评分和意见挖掘.本文借助朴素贝叶斯算法,针对文本正负面进行判别,并且利用C#进行编程实现. 不先介绍点基础? 朴素贝叶斯,真的很朴素 朴素贝叶斯分类算法,是一种有监督学习算法,通过对训练集的学习,基于先验概率与贝叶

【数据挖掘】朴素贝叶斯算法计算ROC曲线的面积

题记:          近来关于数据挖掘学习过程中,学习到朴素贝叶斯运算ROC曲线.也是本节实验课题,roc曲线的计算原理以及如果统计TP.FP.TN.FN.TPR.FPR.ROC面积等等.往往运用ROC面积评估模型准确率,一般认为越接近0.5,模型准确率越低,最好状态接近1,完全正确的模型面积为1.下面进行展开介绍: ROC曲线的面积计算原理 一.朴素贝叶斯法的工作过程框架图 二.利用weka工具,找到训练的预处理数据 1.利用朴素贝叶斯算法对weather.nominal.arff文件进行

数据挖掘|朴素贝叶斯算法

作者:张一 链接:https://zhuanlan.zhihu.com/p/21571692 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 因为后期的项目将涉及到各种各样的价格数据处理问题,所以我们现在开始学习一些简单的数据清洗与算法的知识.关于算法,以前听起来觉得好高大上,现在开始学,觉得书上的描述并不是很通俗易懂,所以用自己的语言来简要写一下这些算法~ 注:非商业转载注明作者即可,商业转载请联系作者授权并支付稿费.本人已授权"维权骑士"网站(ht

朴素贝叶斯算法原理及实现

朴素贝叶斯算法简单高效,在处理分类问题上,是应该首先考虑的方法之一. 1.准备知识 贝叶斯分类是一类分类算法的总称,这类算法均以贝叶斯定理为基础,故统称为贝叶斯分类. 这个定理解决了现实生活里经常遇到的问题:已知某条件概率,如何得到两个事件交换后的概率,也就是在已知P(A|B)的情况下如何求得P(B|A).这里先解释什么是条件概率: 表示事件B已经发生的前提下,事件A发生的概率,叫做事件B发生下事件A的条件概率.其基本求解公式为:. 下面不加证明地直接给出贝叶斯定理: 2.朴素贝叶斯分类 2.1

朴素贝叶斯算法(Naive Bayes)

朴素贝叶斯算法(Naive Bayes) 阅读目录 一.病人分类的例子 二.朴素贝叶斯分类器的公式 三.账号分类的例子 四.性别分类的例子 生活中很多场合需要用到分类,比如新闻分类.病人分类等等. 本文介绍朴素贝叶斯分类器(Naive Bayes classifier),它是一种简单有效的常用分类算法. 回到顶部 一.病人分类的例子 让我从一个例子开始讲起,你会看到贝叶斯分类器很好懂,一点都不难. 某个医院早上收了六个门诊病人,如下表. 症状 职业 疾病 打喷嚏 护士 感冒  打喷嚏 农夫 过敏

Step by Step 改进朴素贝叶斯算法

引言 如果你对naive bayes认识还处于初级阶段,只了解基本的原理和假设,还没有实现过产品级的代码,那么这篇文章能够帮助你一步步对原始的朴素贝叶斯算法进行改进.在这个过程中你将会看到朴素贝叶斯假设的一些不合理处以及局限性,从而了解为什么这些假设在简化你的算法的同时,使最终分类结果变得糟糕,并针对这些问题提出了改进的方法. 朴素贝叶斯(Naive Bayes) 出处: <机器学习>(Machine Learning by Tom M.Mitchell) 符号和术语 假设待分类的实例 X 可