Task 04|基于朴素贝叶斯的文本分类

先了解一下关于朴素贝叶斯的几个小问题:

贝叶斯公式是怎么来的?

首先我们回顾一下什么是条件概率:P(B|A), 意思是在 B 发生的条件下 A 发生的概率,就是下图中 AB 重叠的部分。


若有 n 个条件 B,已知在各个条件 B 发生的情况下 A 发生的概率,要求在这些条件下 A 发生的概率,则要用到全概率公式
P(A) = \Sigma_n P(A|B_n)P(B_n)
若反向思考,已知 B 的概率和 A 的概率,也已知在条件 B 发生的情况下 A 发生的概率,由此可推出贝叶斯公式
P(A|B) = \frac{P(B|A)*P(A)} {P(B)}

朴素贝叶斯为什么“朴素naive”?

朴素贝叶斯(Navie Bayesian)中的“朴素”可以理解为是“简单、理想化”。因为朴素贝叶斯假设分类特征在类确定的条件下都是相互独立的,即满足条件独立假设。这个假设在实际情况下是很难满足的,使朴素贝叶斯法变得简单,有时会牺牲一定的分类准确率。

朴素贝叶斯的工作流程是怎样的?

  • 准备阶段:
    确定特征属性,并对每个特征属性进行适当划分,去除高度相关的属性,然后由人工对一部分待分类项进行分类,形成训练样本集合。这一阶段的输入是所有待分类数据,输出是特征属性和训练样本。
  • 分类器训练阶段:
    计算每个类别在训练样本中的出现频率及每个特征属性划分对每个分类别的条件概率估计,并将结果记录。
  • 应用阶段:
    使用分类器对待分类项进行分类,其输入是分类器和待分类项,输出是待分类项与类别的映射关系,并选出概率值最高所对应的类别。

动手练习

sklearn中的贝叶斯分类器来进行文档分类,文档包括训练数据和测试数据,一共分为4类。
读取文件的函数,这里用到jieba分词工具将文档中的词提取出来:

import os
import jieba
import warnings
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn import metrics

warnings.filterwarnings('ignore')

# 对文本词进行切割,将文本中的词用jieba分词后用空格拼接起来
def cut_words(file_path):
    words_with_spaces = ''
    text = open(file_path, 'r', encoding='gb18030').read()
    text_cut = jieba.cut(text)
    for word in text_cut:
        words_with_spaces += word + ' '
    return words_with_spaces

# 读取目录下的文本文件, 将文本文件和label标记为可训练的数据
def load_file(file_dir, label):
    file_list = os.listdir(file_dir)
    words_list = []
    labels_list = []
    
    for file in file_list:
        file_path = file_dir + '/' + file
        words_list.append(cut_words(file_path))
        labels_list.append(label)
    return words_list, labels_list

训练数据和测试数据分别放在traintest文件夹中,需要用上面的函数读取出来用以训练:


# 训练数据
train_base_dir = 'text classification/train/'
test_base_dir = 'text classification/test/'
text_labels = ['女性', '体育', '文学', '校园']
label_num = len(text_labels)

# 读取数据
def load_data(base_dir):
    data = []
    labels = []
    for i in range(label_num):
        word_list, file_label = load_file(base_dir+text_labels[i], text_labels[i])
        data += word_list
        labels += file_label
    return data, labels
        
# 读取训练数据
train_data, train_labels = load_data(train_base_dir)
# 读取测试数据
test_data, test_labels = load_data(test_base_dir)

还有停用词文件,以免无意义的词影响词频分析:

# 读取停用词
stop_words_path = 'text classification/stop/stopword.txt'
stop_words = open(stop_words_path, 'r', encoding='utf-8').read()
stop_words = stop_words.encode('utf-8').decode('utf-8-sig')
stop_words = stop_words.split('\n')

计算TF-IDF值

什么是 TF-IDF 值呢?
TF-IDF 值是一个统计方法,用以估计某个词语对于文件集或文档库中的其中一个文件的重要程度。
TF 是指 Term Frequency ,单词在该文档中的词频:
TF_{i, j} = \frac{n_{i,j}}{\Sigma_k n_{i,j}}
其中,TF_{i, j}表示第 j 篇文本中第 i 个词的 TF 值,n_{i,j}表示第 j 篇文本中第 i 个词的出现频次, \Sigma_k n_{i,j} 则表示第 j 篇文本中所有词的出现频次,k 表示第 j 篇文本中的词汇量。
IDF 指 Inverse Document Frequency,指单词在整个文档库中的逆词频:
IDF_{i,j} = \log \frac{|D|}{1+| D_{t_i} |}
其中,IDF_{i,j}表示第 j 篇文本中第 i 个词的 IDF 值,|D| 表示数据库中文本的总数,| D_{t_i} |则表示数据库中含词t_i的文本数量,为了防止该词语在语料库中不存在分母为 0 的情况,取1+| D_{t_i} |作为分母,取对数是为了防止\frac{|D|}{1+| D_{t_i} |}过小而不方便计算。
由上两个公式可以看出来,

  • TF 值能体现出词 i 在文本 j 中的重要程度,TF 值越高则该词在文档中越重要
  • IDF 值则体现了词 i 在文本库中的区分度,一个词出现的文档数越少越能把该文档和其他文档区分开来,即 IDF 值越大区分度越高
    TF-IDF 值为:
    TF-IDF_{i,j} = TF_{i,j} * IDF_{i,j}
    因此 TF-IDF 值越高越能将文档分类。
    可以sklearn中的TfidfVectorizer来计算每个单词在每个文档中的 TF-IDF 值,其结果为每个文档中各个词的 TF-IDF 值矩阵。
    由于文本的表示向量维度等同于词典的长度,因此结果将是个系数矩阵。
# 用TF-IDF计算单词的权重
tf = TfidfVectorizer(stop_words = stop_words, max_df = 0.5)

train_features = tf.fit_transform(train_data)
test_features = tf.transform(test_data)

参数 max_df 表示选取词的最大 DF 值,这个很好理解,若一个词的 DF 值很大,说明这个词很常见,对于文档分类的参考价值也就不大了,这里取 0.5

使用贝叶斯分类

在了解了 TF-IDF 的原理后,我们了解到 TF-IDF 矩阵是个稀疏矩阵,而贝叶斯模型的极大似然估计法会求概率值的乘积,若一个词的概率被计算为 0 则会影响整体的结果。
为了解决这样的问题,我们需要做平滑处理。
其中参数 alpha 为平滑参数,

  • alpha = 1 时为 Laplace 平滑,就是采用加 1 的方式来统计没有出现过的单词概率
  • 0 < alpha < 1 时为 Lidstone 平滑,Lidstone 平滑为 Laplace 的一般项,alpha 值越小迭代次数越多,精度越高
    使用多项式贝叶斯分类器:
from sklearn.naive_bayes import MultinomialNB
clf = MultinomialNB(alpha=0.0005).fit(train_features, train_labels)
pred_labels = clf.predict(test_features)

# accuracy
print('accuracy: ', metrics.accuracy_score(test_labels, pred_labels))

最后准确率为93%。

accuracy:  0.93

END

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,843评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,538评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,187评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,264评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,289评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,231评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,116评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,945评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,367评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,581评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,754评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,458评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,068评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,692评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,842评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,797评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,654评论 2 354

推荐阅读更多精彩内容