文章目录

  • 1 文本分类
  • 2 文本数据处理
  • 3 文本数据准备
  • 4 朴素贝叶斯分类建模


1 文本分类

文本分类是现代机器学习应用中的一大模块,更是自然语言处理的基础之一。

文本分类现广泛应用于各个行业领域,如新闻分类、人机写作判断、垃圾邮件识别、情感分类、文案智能生成、商品智能推荐等。


2 文本数据处理

在开始分类之前,我们必须先将文本编码成数字

CountVectorizer类,通过这一类中的功能,可以很容易地实现文本的词频统计与向量化

例如

from sklearn.feature_extraction.text import CountVectorizer
countvec = CountVectorizer() 
x=countvec.fit_transform(['郭靖 和 哀牢山 三十六 剑 。', '黄蓉 和 郭靖 郭靖']) # 一次搞定
type(x)
x.todense() # 将稀疏矩阵直接转换为标准格式矩阵
countvec.get_feature_names() # 词汇列表,实际上就是获取每个列对应的词条
countvec.vocabulary_ # 词条字典

文本分类 nlp 文本分类的应用场景_数据

import pandas as pd
#注意稀疏矩阵是无法输入pandas的
CVresult = pd.DataFrame(x.toarray(),columns = countvec.get_feature_names())
CVresult

因为只有两句话 所以有两行

文本分类 nlp 文本分类的应用场景_朴素贝叶斯_02


如果使用单词计数向量,可能会导致一部分常用词(比如中文中的”的“)频繁出现在我们的矩阵中并且占有很高的权重,对分类来说,这明显是对算法的一种误导。

频繁出现,又没有意义的词,权重占比还高

为了解决这个问题,比起使用次数,我们使用单词在句子中所占的比例来编码我们的单词,这就是我们著名的TF-IDF方法。

3 文本数据准备

这里使用的数据集是sklearn中自带的文本数据集fetch_20newsgroup。这个数据集是20个网络新闻组的语料库,其中包含约2万篇新闻,全部以英文显示

如果是中文文档分类,需要进行分词处理

import jieba
cut = lambda x: " ".join(jieba.lcut(x)) # 这里不做任何清理工作,以保留情感词
data["cleansenten"] = data['文档'].apply(cut ) 
data.head()

下面开始数据集fetch_20newsgroup文档分类

fetch_20newsgroups 中的参数

sklearn.datasets.fetch_20newsgroups (
										data_home=None, 
										subset=’train’, 
										categories=None, 
										shuffle=True,
										random_state=42, 
										remove=(), 
										download_if_missing=True)
  • data_home指的是数据集的地址,如果默认的话,所有的数据都会在’~/scikit_learn_data’文件夹下
  • subset:选择类中包含的数据子集
    输入“train"表示选择训练集,“test"表示输入测试集,“all"表示加载所有的数据
  • categories:可输入None或者数据所在的目录选择一个子集下,不同类型或不同内容的数据所在的目录。如果不输入默认None,则会加载全部的目录。
  • download_if_missing:可选,默认是True如果发现本地数据不全,是否自动进行下载
  • shuffle:布尔值,可不填,表示是否打乱样本顺序对于假设样本之间互相独立并且服从相同分布的算法或模型(比如随机梯度下降)来说可能很重要。
  • remove:是一个元组,用来去除一些停用词的,例如标题引用之类的。

from sklearn.datasets import fetch_20newsgroups
#初次使用这个数据集的时候,会在实例化的时候开始下载
data = fetch_20newsgroups()

#不同类型的新闻
data.target_names
'''
['alt.atheism',
 'comp.graphics',
 'comp.os.ms-windows.misc',
 'comp.sys.ibm.pc.hardware',
 'comp.sys.mac.hardware',
 'comp.windows.x',
 'misc.forsale',
 'rec.autos',
 'rec.motorcycles',
 'rec.sport.baseball',
 'rec.sport.hockey',
 'sci.crypt',
 'sci.electronics',
 'sci.med',
 'sci.space',
 'soc.religion.christian',
 'talk.politics.guns',
 'talk.politics.mideast',
 'talk.politics.misc',
 'talk.religion.misc']
'''

提取数据

import numpy as np
import pandas as pd

# 只提取一部分
# 不同类型或不同内容的数据所在的目录
categories = ["sci.space" #科学技术 - 太空
              ,"rec.sport.hockey" #运动 - 曲棍球
              ,"talk.politics.guns" #政治 - 枪支问题
              ,"talk.politics.mideast"] #政治 - 中东问题

# 选择训练集 ,数据中包括4中类别
train = fetch_20newsgroups(subset="train",categories = categories)
# 选择测试集 ,数据中包括4中类别
test = fetch_20newsgroups(subset="test",categories = categories)

可以看到,训练集数据有 2303 条,标签类别为4种

文本分类 nlp 文本分类的应用场景_数据_03

测试集数据有 1533 条,标签类别为4种

文本分类 nlp 文本分类的应用场景_朴素贝叶斯_04

train.target_names
'''
['rec.sport.hockey',
 'sci.space',
 'talk.politics.guns',
 'talk.politics.mideast']
'''

#查看总共有多少篇文章存在
len(train.data)  # 2303篇文章


#查看标签
np.unique(train.target)#  array([0, 1, 2, 3], dtype=int64)
len(train.target) # 2303


# 查看样本均衡情况
pd.DataFrame(train.target).value_counts()/len(train.target)
'''
0    0.260530
1    0.257490
3    0.244898
2    0.237082
dtype: float64
'''
'''

准备数据

Xtrain = train.data
Xtest = test.data
Ytrain = train.target
Ytest = test.target

文本分类 nlp 文本分类的应用场景_朴素贝叶斯_05


使用TF-IDF将文本数据编码

from sklearn.feature_extraction.text import TfidfVectorizer as TFIDF
# 用训练集拟合完毕的类 对训练集和测试集分别进行转换
tfidf = TFIDF().fit(Xtrain)
Xtrain_ = tfidf.transform(Xtrain)
Xtest_ = tfidf.transform(Xtest)

Xtrain_
'''
<2303x40725 sparse matrix of type '<class 'numpy.float64'>'
	with 430306 stored elements in Compressed Sparse Row format>
'''
# 2303篇文章,40725个不重复的单词,每一行代表一个文档


Xtest_ 
'''
<1533x40725 sparse matrix of type '<class 'numpy.float64'>'
	with 261060 stored elements in Compressed Sparse Row format>
'''
tosee = pd.DataFrame(Xtrain_.toarray(),columns=tfidf.get_feature_names())
tosee.head()
'''
    00       000  0000  00000  000000  ...   zy  zyg   zz  zz_g9q3  zzzzzz
0  0.0  0.000000   0.0    0.0     0.0  ...  0.0  0.0  0.0      0.0     0.0
1  0.0  0.000000   0.0    0.0     0.0  ...  0.0  0.0  0.0      0.0     0.0
2  0.0  0.058046   0.0    0.0     0.0  ...  0.0  0.0  0.0      0.0     0.0
3  0.0  0.000000   0.0    0.0     0.0  ...  0.0  0.0  0.0      0.0     0.0
4  0.0  0.000000   0.0    0.0     0.0  ...  0.0  0.0  0.0      0.0     0.0

[5 rows x 40725 columns]
'''
tosee.shape  #  (2303, 40725)

4 朴素贝叶斯分类建模

开始建模(朴素贝叶斯模型Naive Bayesian)

朴素贝叶斯方法是一组基于贝叶斯定理与特征条件独立假设的监督学习算法,在给定类变量值的情况下,朴素假设每对特征之间存在条件独立性。朴素贝叶斯原理简单,需要关注的参数比较少,也很容易实现。

朴素贝叶斯最擅长的领域是文本分析,包括:文本分类、垃圾邮件过滤、情感分析等

文本分类 nlp 文本分类的应用场景_数据_06

sklearn 库中的 naive_bayes 模块实现了 5 种朴素贝叶斯算法(多项式朴素贝叶斯MultinomialNB、高斯朴素贝叶斯GaussianNB、伯努利朴素贝叶斯BernoulliNB、分类朴素贝叶斯CategoricalNB、补充朴素贝叶斯ComplementNB)

  • 1.MultinomialNB
    假设特征的先验概率为多项式分布,处理离散型变量,即多项式朴素贝叶斯分类器适用于具有离散特征的分类(例如,用于文本分类的字数统计)。如果样本特征的分大部分是多元离散值,使用MultinomialNB比较合适。
  • 2.GaussianNB
    假设先验概率为高斯分布,处理连续型变量,GaussianNB 是一个非线性模型,不支持稀疏矩阵,因此,如果样本特征的分布大部分是连续值,使用GaussianNB会比较好。
  • 3.BernoulliNB
    假设先验为伯努利分布的朴素贝叶斯,处理离散型变量。如果样本特征是二元离散值或者很稀疏的多元离散值,使用BernoulliNB会比较好。
  • 4.CategoricalNB
  • 5.ComplementNB
    多项式朴素贝叶斯算法的一种改进。

注意:朴素贝叶斯是一个不建模的算法

下面使用多项式朴素贝叶斯模型、补充朴素贝叶斯模型、伯努利朴素贝叶斯模型对文档进行分类

from sklearn.naive_bayes import MultinomialNB, ComplementNB, BernoulliNB
from sklearn.metrics import brier_score_loss as BS
# 布里尔分数
'''
有两种流行的测度可用于评估预测的概率,分别是:
对数损失(Log Loss)
Brier分数 (Brier Score)

Brier分数是一个评价频率预测准确度的指标,它计算了预测概率和期望值之间的均方误差,适用于具有多类别的问题
'''

# 多项式朴素贝叶斯、补充朴素贝叶斯、伯努利朴素贝叶斯

name = ["Multinomial","Complement","Bournulli"]
models = [MultinomialNB(),ComplementNB(),BernoulliNB()]

for name,clf in zip(name,models):
    # 训练
    clf.fit(Xtrain_,Ytrain)
    # 预测
    y_pred = clf.predict(Xtest_)
    # 预测概率
    proba = clf.predict_proba(Xtest_)
    # 得分
    score = clf.score(Xtest_,Ytest)
    print(name)
    # 得分
    print("\tAccuracy:{:.3f}".format(score))
    print("\n")

'''
Multinomial
        Accuracy:0.975


Complement
        Accuracy:0.986


Bournulli
        Accuracy:0.902
'''

从结果上来看,多项式朴素贝叶斯模型与补充朴素贝叶斯模型的效果都很不错,补充朴素贝叶斯模型的精确度最高。

接下来,可以使用概率校准来试试看能否让模型进一步突破

概率校准

9种模型 添加6个校准的模型

from sklearn.calibration import CalibratedClassifierCV

# 组合  概率校准
name = ["Multinomial",
        "Multinomial + Isotonic",
        "Multinomial + Sigmoid",
        "Complement",
        "Complement + Isotonic",
        "Complement + Sigmoid",
        "Bernoulli",
        "Bernoulli + Isotonic",
        "Bernoulli + Sigmoid"]

# 9种模型  添加6个校准的模型
models = [
    MultinomialNB(),
    CalibratedClassifierCV(MultinomialNB(), cv=2, method='isotonic'),
    CalibratedClassifierCV(MultinomialNB(), cv=2, method='sigmoid'),
    
    ComplementNB(),
    CalibratedClassifierCV(ComplementNB(), cv=2, method='isotonic'),
    CalibratedClassifierCV(ComplementNB(), cv=2, method='sigmoid'),
    
    BernoulliNB(),
    CalibratedClassifierCV(BernoulliNB(), cv=2, method='isotonic'),
    CalibratedClassifierCV(BernoulliNB(), cv=2, method='sigmoid')
    ]

for name,clf in zip(name,models):
    clf.fit(Xtrain_,Ytrain)
    y_pred = clf.predict(Xtest_)
    proba = clf.predict_proba(Xtest_)
    score = clf.score(Xtest_,Ytest)
    print(name)
    print("\tAccuracy:{:.3f}".format(score))
    print("\n")

'''
Multinomial
        Accuracy:0.975


Multinomial + Isotonic
        Accuracy:0.973


Multinomial + Sigmoid
        Accuracy:0.973


Complement
        Accuracy:0.986


Complement + Isotonic
        Accuracy:0.985


Complement + Sigmoid
        Accuracy:0.986


Bernoulli
        Accuracy:0.902


Bernoulli + Isotonic
        Accuracy:0.952


Bernoulli + Sigmoid
        Accuracy:0.879
'''

可以观察到,多项式朴素分布下无论如何调整,算法的效果都不如补充朴素贝叶斯好。

因此我们在分类的时候,应该选择补集朴素贝叶斯。

对于补集朴素贝叶斯来说,使用Sigmoid进行概率校准的模型综合最优秀:准确率最高,对数损失和布里尔分数都在0.1以下,可以说是非常理想的模型了

只要能够提供足够的数据,合理利用高维数据进行训练,朴素贝叶斯就可以达到意想不到的效果。