贝叶斯机器学习系列:
贝叶斯①——贝叶斯原理篇(联合概率&条件概率&贝叶斯定理&拉普拉斯平滑)
贝叶斯②——贝叶斯3种分类模型及Sklearn使用(高斯&多项式&伯努利)
贝叶斯③——Python实现贝叶斯文本分类(伯努利&多项式模型对比)
贝叶斯⑤——搜狗新闻分类实战(jieba + TF-IDF + 贝叶斯)
贝叶斯⑥——银行借贷模型(贝叶斯与决策树对比)
20 newsgroups数据集18000篇新闻文章,一共涉及到20种话题,所以称作20 newsgroups text dataset,分文两部分:训练集和测试集,通常用来做文本分类。sklearn提供了该数据的接口:sklearn.datasets.fetch_20newsgroups
from sklearn.datasets import fetch_20newsgroups
import numpy as np
categories = ['alt.atheism', 'soc.religion.christian', 'comp.graphics', 'sci.med']
train_data = fetch_20newsgroups(subset='train', shuffle=True, categories=categories,random_state=42) # subset可以选择train(训练集),test(测试集),all(所有数据集)
print(train_data.data) # train_data返回是一个含有数据,类别和类别名称的词典,通过data,target,target_name键可以分别输出
常用的文本处理方式有两种:
1、 CountVectorizer + TfidfTransformer
① CountVectorizer: 将分词后的文本转化成词频矩阵,就是先将训练样本所有的单词都输入到一个词典中,然后统计每一篇文档每个词出现的次数来作为文档的向量,通过CountVectorizer().fit_transform()实现
常用的4个方法:
CountVectorizer().get_feature_names():获得特征名称
CountVectorizer().vocabulary_: 获得词典及对应的位置下标
CountVectorizer().fit_transform(data): 获得词频的稀疏矩阵表示
CountVectorizer().fit_transform(data).toarray(): 获得词频的正常矩阵表示
② TfidfTransformer:根据词频计算TF-IDF 权重矩阵,这里解释下TF-IDF:
TF: 词频,统计每个词在文档中出现的频率,一般是用每个词出现的次数/文档总词数进行归一化;
IDF:逆向文件频率,是用所有文档数/出现某个词的文档数目,某个词在越多文档中出现,这个值就越接近于1,再取对数,就会越接近于0;为了防止某个词没有在训练中出现导致分母为0的情况,会给分母+1
TF-IDF = TF × IDF
某一特定文件内的高词语频率,以及该词语在整个文件集合中的低文件频率,可以产生出高权重的TF-IDF。因此,TF-IDF倾向于过滤掉常见的词语,保留重要的词语
# 特征向量化&TF-IDF
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
vector = CountVectorizer()
train_data = vector.fit_transform(train_data.data)
np.set_printoptions(threshold=np.nan) # 设置显示矩阵所有行列
print('特征个数:', len(vector.get_feature_names()))
print('特征词:', vector.vocabulary_)
print('词频:', train_data)
transfomer = TfidfTransformer()
tf_train_data = transfomer.fit_transform(train_data)
print('词频矩阵', tf_train_data.toarray()[1])
可以看出特征数高达35788,在如此多的特征下,矩阵就变得非常稀疏,这是文本分类的一大特征。代码还可以再简洁一点,如下,结果一样:
vector = CountVectorizer()
transfomer = TfidfTransformer()
tf_train_data = transfomer.fit_transform(vector.fit_transform(train_data.data))
2、TfidfVectorizer
TfidfVectorizer = CountVectorizer + TfidfTransformer,效果一样,只是一步到位了。
TfidfVectorizer 有几个参数需要注意下:
① input:string{‘filename’, ‘file’, ‘content’}
如果是’filename’,序列作为参数传递给拟合器,预计为文件名列表,这需要读取原始内容进行分析, 如果是’file’,序列项目必须有一个”read“的方法(类似文件的对象),被调用作为获取内存中的字节数, 否则,输入预计为序列串,或字节数据项都预计可直接进行分析。
② encoding:string, ‘utf-8’ by default
如果给出要解析的字节或文件,此编码将用于解码
③ max_df: float in range [0.0, 1.0] or int, optional, 1.0 by default
当构建词汇表时,严格忽略高于给出阈值的文档频率的词条,语料指定的停用词。如果是浮点值,该参数代表文档的比例,整型绝对计数值,如果词汇表不为None,此参数被忽略。
④ min_df:与max_df正好相反
from sklearn.feature_extraction.text import TfidfVectorizer
np.set_printoptions(threshold=np.nan) # 设置显示矩阵所有行列
tfidf_transformer = TfidfVectorizer()
tf_train_data = tfidf_transformer.fit_transform(train_data.data)
print(tfidf_transformer) # 输出参数
print(tf_train_data)# 稀疏矩阵表示法
print(tf_train_data.toarray()[1]) # 一般矩阵表示法
print(tf_train_data.todense()[1]) # 一般矩阵表示法
print(tfidf_transformer.get_feature_names()) # 获得特征名
print(tfidf_transformer.idf_[1]) # 输出IDF值
print(tfidf_transformer.vocabulary_) # 词语与列的对应关系
from sklearn.naive_bayes import MultinomialNB
from sklearn import metrics
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
clf = MultinomialNB(fit_prior=True) # fit_prior表示通过训练样本计算类别先验概率,如果是False,则每类别概率一样
clf.fit(tf_train_data,train_data.target)
test_data = fetch_20newsgroups(subset='test', shuffle=True,categories=categories,random_state=34) # 导入测试样本
tf_test_data = tfidf_transformer.transform(test_data.data) # 用之前的tf-idf模型直接转化
y_pred = clf.predict(tf_test_data)
print('训练集分数:', clf.score(tf_test_data,test_data.target))
print('测试集分数:', metrics.accuracy_score(y_pred,test_data.target))
print('混淆矩阵:', confusion_matrix(y_pred,test_data.target))
print('分类报告:', classification_report(y_pred,test_data.target))
训练集的准确率高达96%, 测试样本高达83%,也还算非常不错的结果了。混淆矩阵对角线上的数字也是远远大于非对角线上,侧面验证了分类效果