机器学习与贝叶斯分类器

朴素贝叶斯是一个很不错的分类器,在使用朴素贝叶斯分类器划分邮件有关于朴素贝叶斯的简单介绍。

一个样本有n个特征,分别用x1,x2,...,xn表示,将其划分到类yk的可能性P(yk|x1,x2,...,xn)为:

P(yk|x1,x2,...,xn)=P(yk)ni=1P(xi|yk)

上式中等号右侧的各个值可以通过训练得到。根据上面的公式可以求的某个数据属于各个分类的可能性(这些可能性之和不一定是1),该数据应该属于具有最大可能性的分类中。

一般来说,如果一个样本没有特征xi,那么P(xi|yk)将不参与计算。不过下面的伯努利模型除外。

以上是朴素贝叶斯的最基本的内容。

高斯模型


有些特征可能是连续型变量,比如说人的身高,物体的长度,这些特征可以转换成离散型的值,比如如果身高在160cm以下,特征值为1;在160cm和170cm之间,特征值为2;在170cm之上,特征值为3。也可以这样转换,将身高转换为3个特征,分别是f1、f2、f3,如果身高是160cm以下,这三个特征的值分别是1、0、0,若身高在170cm之上,这三个特征的值分别是0、0、1。不过这些方式都不够细腻,高斯模型可以解决这个问题。高斯模型假设这些一个特征的所有属于某个类别的观测值符合高斯分布,也就是:

P(xi|yk)=12πσ2yk√exp((xiμyk)22σ2yk)

下面看一个sklearn中的示例:

>>> from sklearn import datasets
>>> iris = datasets.load_iris()
>>> iris.feature_names  # 四个特征的名字
['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)'] >>> iris.data array([[ 5.1, 3.5, 1.4, 0.2], [ 4.9, 3. , 1.4, 0.2], [ 4.7, 3.2, 1.3, 0.2], [ 4.6, 3.1, 1.5, 0.2], [ 5. , 3.6, 1.4, 0.2], [ 5.4, 3.9, 1.7, 0.4], [ 4.6, 3.4, 1.4, 0.3], [ 5. , 3.4, 1.5, 0.2], ...... [ 6.5, 3. , 5.2, 2. ], [ 6.2, 3.4, 5.4, 2.3], [ 5.9, 3. , 5.1, 1.8]]) #类型是numpy.array >>> iris.data.size 600 #共600/4=150个样本 >>> iris.target_names array(['setosa', 'versicolor', 'virginica'], dtype='|S10') >>> iris.target array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,....., 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ......, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]) >>> iris.target.size 150 >>> from sklearn.naive_bayes import GaussianNB >>> clf = GaussianNB() >>> clf.fit(iris.data, iris.target) >>> clf.predict(iris.data[0]) array([0]) # 预测正确 >>> clf.predict(iris.data[149]) array([2]) # 预测正确 >>> data = numpy.array([6,4,6,2]) >>> clf.predict(data) array([2]) # 预测结果很合理 

多项式模型


该模型常用于文本分类,特征是单词,值是单词的出现次数。

P(xi|yk)=Nykxi+αNyk+αn

其中,Nykxi是类别yk下特征xi出现的总次数;Nyk是类别yk下所有特征出现的总次数。对应到文本分类里,如果单词word在一篇分类为label1的文档中出现了5次,那么Nlabel1,word的值会增加5。如果是去除了重复单词的,那么Nlabel1,word的值会增加1。n是特征的数量,在文本分类中就是去重后的所有单词的数量。α的取值范围是[0,1],比较常见的是取值为1。

待预测样本中的特征xi在训练时可能没有出现,如果没有出现,则Nykxi值为0,如果直接拿来计算该样本属于某个分类的概率,结果都将是0。在分子中加入α,在分母中加入αn可以解决这个问题。

下面的代码来自sklearn的示例:

>>> import numpy as np
>>> X = np.random.randint(5, size=(6, 100)) >>> y = np.array([1, 2, 3, 4, 5, 6]) >>> from sklearn.naive_bayes import MultinomialNB >>> clf = MultinomialNB() >>> clf.fit(X, y) MultinomialNB(alpha=1.0, class_prior=None, fit_prior=True) >>> print(clf.predict(X[2])) [3] 

值得注意的是,多项式模型在训练一个数据集结束后可以继续训练其他数据集而无需将两个数据集放在一起进行训练。在sklearn中,MultinomialNB()类的partial_fit()方法可以进行这种训练。这种方式特别适合于训练集大到内存无法一次性放入的情况。

在第一次调用partial_fit()时需要给出所有的分类标号。

>>> import numpy
>>> from sklearn.naive_bayes import MultinomialNB
>>> clf = MultinomialNB() >>> clf.partial_fit(numpy.array([1,1]), numpy.array(['aa']), ['aa','bb']) GaussianNB() >>> clf.partial_fit(numpy.array([6,1]), numpy.array(['bb'])) GaussianNB() >>> clf.predict(numpy.array([9,1])) array(['bb'], dtype='|S2') 

伯努利模型


伯努利模型中,对于一个样本来说,其特征用的是全局的特征。

在伯努利模型中,每个特征的取值是布尔型的,即true和false,或者1和0。在文本分类中,就是一个特征有没有在一个文档中出现。

如果特征值xi值为1,那么

P(xi|yk)=P(xi=1|yk)

如果特征值xi值为0,那么

P(xi|yk)=1P(xi=1|yk)

这意味着,“没有某个特征”也是一个特征。 下面的示例来自sklearn官方文档:

>>> import numpy as np
>>> X = np.random.randint(2, size=(6, 100)) >>> Y = np.array([1, 2, 3, 4, 4, 5]) >>> from sklearn.naive_bayes import BernoulliNB >>> clf = BernoulliNB() >>> clf.fit(X, Y) BernoulliNB(alpha=1.0, binarize=0.0, class_prior=None, fit_prior=True) >>> print(clf.predict(X[2])) [3] 

BernoulliNB()类也有partial_fit()函数。

多项式模型和伯努利模型在文本分类中的应用


基于naive bayes的文本分类算法给出了很好的解释。

在多项式模型中:

在多项式模型中, 设某文档d=(t1,t2,…,tk),tk是该文档中出现过的单词,允许重复,则

先验概率P(c)= 类c下单词总数/整个训练样本的单词总数

类条件概率P(tk|c)=(类c下单词tk在各个文档中出现过的次数之和+1)/(类c下单词总数+|V|)

V是训练样本的单词表(即抽取单词,单词出现多次,只算一个),|V|则表示训练样本包含多少种单词。 P(tk|c)可以看作是单词tk在证明d属于类c上提供了多大的证据,而P(c)则可以认为是类别c在整体上占多大比例(有多大可能性)。

在伯努利模型中:

P(c)= 类c下文件总数/整个训练样本的文件总数

P(tk|c)=(类c下包含单词tk的文件数+1)/(类c下单词总数+2)



使用sklearn自带的贝叶斯分类器进行文本分类和参数调优

96 
YoghurtIce 
2016.01.18 20:57*  字数 1177  阅读 8936 评论 4

Part 1: 本篇内容简介

在前一篇文章完全手写,自给自足完成贝叶斯文本分类中,我们使用首先假设在文档中出现的单词彼此独立,利用贝叶斯定理,完成了一个简单的文本分类器的编写,在真实数据的测试上,显示了良好的效果。
其实要是了解sklearn的人都应该知道,这个python的机器学习库,实现了我们常用的大部分机器学习算法,免除了我们重复造轮子的痛苦。我们使用和上一篇博客同样的数据,使用sklearn自带的贝叶斯分类器完成文本分类,同时和上一篇文章手写的分类器,进行分类精度、速度、灵活性对比。

Part 2: 朴素贝叶斯的在文本分类中常用模型:多项式、伯努利

这部分的内容,我参考了朴素贝叶斯分类器的应用这篇文章。朴素贝叶斯分类器是一种有监督学习,常见有两种模型,多项式模型(multinomial model)即为词频型和伯努利模(Bernoulli model)即文档型。二者的计算粒度不一样,多项式模型以单词为粒度,伯努利模型以文件为粒度,因此二者的先验概率和类条件概率的计算方法都不同。计算后验概率时,对于一个文档d,多项式模型中,只有在d中出现过的单词,才会参与后验概率计算,伯努利模型中,没有在d中出现,但是在全局单词表中出现的单词,也会参与计算,不过是作为“反方”参与的。这里暂不虑特征抽取、为避免消除测试文档时类条件概率中有为0现象而做的取对数等问题。

Part 2.1: 多项式模型
多项式模型
Part 2.2: 伯努利模型
伯努利模型
Part 2.3: 两个模型的区别
4.png

Part 3:在真实数据上的实验结果

和上一篇博客一样,我使用相同的数据,我这里使用在康奈尔大学下载的2M影评作为训练数据和测试数据,里面共同、共有1400条,好评和差评各自700条,我选择总数的70%作为训练数据,30%作为测试数据,来检测sklearn自带的贝叶斯分类器的分类效果。数据的下载链接见前一篇博客,或者直接邮件找我。

def get_dataset():
    data = []
    for root, dirs, files in os.walk(r'E:\研究生阶段课程作业\python\好玩的数据分析\朴素贝叶斯文本分类\tokens\neg'):
        for file in files:
            realpath = os.path.join(root, file)
            with open(realpath, errors='ignore') as f:
                data.append((f.read(), 'bad'))
    for root, dirs, files in os.walk(r'E:\研究生阶段课程作业\python\好玩的数据分析\朴素贝叶斯文本分类\tokens\pos'):
        for file in files:
            realpath = os.path.join(root, file)
            with open(realpath, errors='ignore') as f:
                data.append((f.read(), 'good'))
    random.shuffle(data)

    return data
data = get_dataset()

以上的代码就是读取全部数据,包括训练集和测试集,并随机打乱,返回打乱后的结果。

def train_and_test_data(data_):
    filesize = int(0.7 * len(data_))
    # 训练集和测试集的比例为7:3
    train_data_ = [each[0] for each in data_[:filesize]]
    train_target_ = [each[1] for each in data_[:filesize]]

    test_data_ = [each[0] for each in data_[filesize:]]
    test_target_ = [each[1] for each in data_[filesize:]]

    return train_data_, train_target_, test_data_, test_target_
train_data, train_target, test_data, test_target = train_and_test_data(data)

以上的代码是用来划分训练集和测试集。按照7:3的比例划分。

from sklearn.naive_bayes import MultinomialNB
from sklearn.pipeline import Pipeline
from sklearn.feature_extraction.text import TfidfVectorizer, HashingVectorizer, CountVectorizer
from sklearn import metrics
from sklearn.naive_bayes import BernoulliNB

nbc = Pipeline([
    ('vect', TfidfVectorizer(
                         
    )),
    ('clf', MultinomialNB(alpha=1.0)),
])
nbc_6.fit(train_data, train_target)    #训练我们的多项式模型贝叶斯分类器
predict = nbc_6.predict(test_data)  #在测试集上预测结果
count = 0                                      #统计预测正确的结果个数
for left , right in zip(predict, test_target):
      if left == right:
            count += 1
print(count/len(test_target))
out: 0.793

和我们上一篇完全手写的贝叶斯分类器相比,使用sklearn自带的多项式模型贝叶斯分类器,使用相同的训练集和测试集,结果后者在测试集上的精度达到了79%,比我们原始手写的精度高出将近10%百分点,效果显而易见,并且训练和分类的速度也大大提高。下面我们使用sklearn自带的伯努利模型分类器进行实验。

nbc_1= Pipeline([
    ('vect', TfidfVectorizer(
                         
    )),
    ('clf', BernoulliNB(alpha=0.1)),
])
predict = nbc_1.predict(test_data)  #在测试集上预测结果
count = 0                                      #统计预测正确的结果个数
for left , right in zip(predict, test_target):
      if left == right:
            count += 1
print(count/len(test_target))
out: 0.781

和多项式模型相比,使用伯努利模型的贝叶斯分类器,在文本分类方面的精度相比,差别不大,我们可以针对我们面对的具体问题,进行实验,选择最为合适的分类器。

Part 4:总结

sklearn真是太强大了,里面分装了绝大部分我们常见的机器学习算法,熟悉这些算法的用法,可以让我们省去重复造轮子的时间,把更多的精力面对我们要解决的问题。所以,如果你不是特别的强迫症患者,还是使用自带的算法,因为这些自带的算法都是经过很多人检验,优化,兼顾速度和精度上的优点。本文选用的训练数据和测试数据都可以从前一篇博客中下载到,如果你嫌麻烦,那么可以直接问我要所有的源代码和数据。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值