Task5 朴素贝叶斯、SVM、LDA主题模型
任务
- 朴素贝叶斯
-
朴素贝叶斯的原理
-
利用朴素贝叶斯模型进行文本分类
- SVM模型
- SVM的原理
- 利用SVM模型进行文本分类
- LDA主题模型
- pLSA、共轭先验分布
- LDA
- 使用LDA生成主题特征,在之前特征的基础上加入主题特征进行文本分类
朴素贝叶斯
- 朴素贝叶斯的原理
朴素贝叶斯被称为朴素是因为引入了几个假设:
贝叶斯公式如下:
换成分类任务的表达式:
1.每个词都是独立的特征
2.假设所有词相互条件独立
朴素贝叶斯公式为:
- 朴素贝叶斯模型进行文本分类
朴素贝叶斯是单独考量每一唯独特征被分类的条件概率,进而综合这些概率并对其所在的特征向量做出分类预测;
朴素贝叶斯的基本数据假设是:各个维度上的特征被分类的条件概率之间是相互独立的,它经常被应用在文本分类中,包括互联网新闻的分类,垃圾邮件的筛选
下面采用新闻分类为示例:
- 首先获取fetch_20newsgroups数据集中的所有数据, 并输出数据共有多少条
from sklearn.datasets import fetch_20newsgroups
# 获取数据
news = fetch_20newsgroups(subset='all')
# 输出数据长度
print(len(news.data))
# 查看新闻类别
pprint(list(news.target_names))
可以看到数据共有18846篇文章,一共涉及到20种话题
数据集信息
- 对数据进行预处理
- 划分数据集:20%的数据作为测试集
- 文本特征向量化
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import CountVectorizer
def pre_news(data):
'''
数据预处理:
划分训练集,测试集
文本特征向量化
'''
# 随机采样20%作为测试集
X_train, X_test, y_train, y_test = train_test_split(data.data,
data.target,
test_size = 0.2,
random_state=33)
# 文本特征向量化
vec = CountVectorizer()
X_train = vec.fit_transform(X_train)
X_test = vec.transform(X_test)
return X_train, X_test, y_train, y_test
# 数据预处理
X_train, X_test, y_train, y_test = pre_news(news)
- 使用朴素贝叶斯进行训练并预测
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import classification_report
def train_model_bayes(data, X_train, y_train, X_test, y_test):
'''
使用朴素贝叶斯进行训练并预测
'''
clf = MultinomialNB()
clf.fit(X_train, y_train)
y_pre = clf.predict(X_test)
# 获取结果报告
print('acc:', clf.score(X_test, y_test))
print(classification_report(y_test, y_pre, target_names=data.target_names))
return y_pre
# 使用朴素贝叶斯进行训练
y_pre = train_model_bayes(news, X_train, y_train, X_test, y_test)
朴素贝叶斯模型被广泛应用于海量互联网分类任务中,其特点如下:
1.模型预测所需要的参数规模从幂指数量级向线性量级减少
2.对内存的消耗和计算时间大大减少
3.受强假设的影响,模型训练时无法将各个特征之间的联系考量在内,导致当特征关联性较强时分类效果不佳
拓展:高斯模型、伯努利模型使用
- 高斯模型
高斯模型可以解决对连续型变量的处理的问题,高斯模型假设这些特征的所有属于某个类别的观测值符合高斯分布,使用方法如下:
from sklearn.naive_bayes import GaussianNB
from sklearn.metrics import confusion_matrix
def correct_rate(predict_labels, y):
# 查看预测对了几个
n = 0
for i in range(len(predict_labels)):
if (predict_labels[i] == y[i]):
n = n + 1
print('高斯贝叶斯:')
# 输出正确率
print(n/499.0)
return n
# 高斯贝叶斯
def train_model_GaussianNB():
pass
clf3 = GaussianNB()
# 训练模型
clf3.fit(X[499:], y[499:])
predict_labels = clf3.predict(X[0:499])
n = correct_rate(predict_labels, y)
# 混淆矩阵
confusion_matrix(y[0:499], predict_labels)
- 伯努利模型
from sklearn.naive_bayes import BernoulliNB
# 伯努利模型
def train_model_BernoulliNB():
pass
clf2 = BernoulliNB()
clf2.fit(X[499:], y[499:])
predict_labels = clf2.predict(X[0:499])
n = correct_rate(predict_labels, y)
# 混淆矩阵
confusion_matrix(y[0:499], predict_labels)
补充:文本分类是作为离散型数据的。朴素贝叶斯用于很多方面,数据就会有连续和离散的,连续型时可用正态分布,还可用区间,将数据的各属性分成几个区间段进行概率计算,测试时看其属性的值在哪个区间就用哪个条件概率。再有TF、TDIDF,这些只是描述事物属性时的不同计算方法,例如文本分类时,可以用单词在本文档中出现的次数描述一个文档,可以用出现还是没出现即0和1来描述,还可以用单词在本类文档中出现的次数与这个单词在剩余类出现的次数(降低此属性对某类的重要性)相结合来表述。
https://blog.csdn.net/u013710265/article/details/72780520
SVM
- SVM原理
Svm(support Vector Mac)又称为支持向量机,是一种二分类的模型,支持向量机可以分为线性核非线性两大类。其主要思想为找到空间中的一个更够将所有数据样本划开的超平面,并且使得本本集中所有数据到这个超平面的距离最短。
SVM算法原理参照:https://blog.csdn.net/d__760/article/details/80387432
- 利用SVM模型进行文本分类
- 使用梯度下降法(SGD),用于判断使用凸loss函数(convex loss function)的分类器(SVM或logistic回归),当
loss='hinge'
:求解线性SVM的分类器,使用方法如下:- 读取数据并且对数据进行预处理,与上文贝叶斯使用同样的方法,这里不过多赘述
- 使用SVM进行新闻分类,并评价
from sklearn.linear_model import SGDClassifier
from sklearn.metrics import classification_report
import numpy as np
def train_model_svm(data, X_train, X_test, y_train, y_test):
'''
SVM进行新闻分类
'''
svm_clf = SGDClassifier(loss='hinge',
penalty='l2',
alpha=8e-5,
max_iter=5,
random_state=50)
svm_clf.fit(X_train, y_train)
y_pre = svm_clf.predict(X_test)
# 输出准确率
print('acc:', np.mean(y_test == y_pre))
# 获取结果报告
print(classification_report(y_test, y_pre, target_names=data.target_names))
参数设置如下:https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.SGDClassifier.html
- 使用
sklearn.svm.svc
进行中文文本分类
def train_model_svc(data, target_names, X_train, X_test, y_train, y_test):
'''
SVM进行新闻分类
'''
svm_clf = svm.SVC(C=10.0, # 惩罚系数
cache_size=200, # 缓冲大小,限制计算量大小
class_weight=None, # 权重设置
coef0=0.0, # 核函数常数,默认为0
decision_function_shape=None, # 原始的SVM只适用于二分类问题
degree=3, # 当指定kernel为'poly'时,表示选择的多项式的最高次数,默认为三次多项式
gamma='auto', # 核函数系数,默认是'auto',那么将会使用特征位数的倒数,即1 / n_features
kernel='rbf', # 算法中采用的核函数类型, 默认的是"RBF",即径向基核,也就是高斯核函数
max_iter=-1, # 最大迭代次数,默认-1
probability=False, # 是否使用概率估计,默认是False
random_state=None, # 在使用SVM训练数据时,要先将训练数据打乱顺序,用来提高分类精度,这里就用到了伪随机序列。如果该参数给定的是一个整数,则该整数就是伪随机序列的种子值
shrinking=True, # 是否进行启发式
tol=0.001, # 残差收敛条件,默认是0.0001
verbose=False) # 是否启用详细输出
svm_clf.fit(X_train, y_train)
y_pre = svm_clf.predict(X_test)
# 输出准确率
print('acc:', np.mean(y_test == y_pre))
# 获取结果报告
print(classification_report(y_test, y_pre, target_names=target_names))
参数设置如下:https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html#sklearn.svm.SVC
LDA主题模型
LDA是一种文档主题生成模型,也称为一个三层贝叶斯概率模型,包含词、主题和文档三层结构。
生成模型:我们认为一篇文章的每个词都是通过“以一定概率选择了某个主题,并从这个主题中以一定概率选择某个词语”这样一个过程得到。文档到主题服从多项式分布,主题到词服从多项式分布。
LDA是一种非监督机器学习技术,可以用来识别大规模文档集(document collection)或语料库(corpus)中潜藏的主题信息。
* 采用了词袋的方法,把每一篇文档看做为一个词频向量;
* 每一篇文档代表了一些主题所构成的一个概率分布,而每一个主题又代表了很多单词所构成的一个概率分布。
- 使用LDA生成主题特征,在之前特征的基础上加入主题特征进行文本分类
- 加载lda中的数据
import lda.datasets
def load_data():
'''
加载lda中的数据
'''
X = lda.datasets.load_reuters()
vocab = lda.datasets.load_reuters_vocab()
titles = lda.datasets.load_reuters_titles()
return X, vocab, titles
X, vocab, titles = load_data()
- 指定主题,进行迭代
#指定11个主题,500次迭代
model = lda.LDA(random_state=1, n_topics=11, n_iter=1000)
model.fit(X)
- 查看主题-单词分布
# 主题单词分布
topic_word = model.topic_word_
print('type(topic_word):{}'.format(type(topic_word)))
print('shape:{}'.format(topic_word.shape))
- 获取每个topic下权重最高的10个单词
n = 10
for i, topic_dist in enumerate(topic_word):
topic_words = np.array(vocab)[np.argsort(topic_dist)][:-(n+1):-1]
print('topic {}\n -{}'.format(i, ' '.join(topic_words)).encode('utf-8'))
- 查看文档主题分布
#文档主题分布:
doc_topic = model.doc_topic_
print("type(doc_topic): {}".format(type(doc_topic)))
print("shape: {}".format(doc_topic.shape))
- 输入前10篇文章最可能的topic
# 输入前10篇文章最可能的topic
for n in range(20):
topic_most_pr = doc_topic[n].argmax()
print('doc: {} topic: {}'.format(n, topic_most_pr))
- 利用gensim调用LDA
- 首先读取数据
- 利用
doc2bow
将文本转化为词袋模型 - 调用LDA模型并指定主题数量
- 检查结果
from gensim.test.utils import common_texts
from gensim.corpora.dictionary import Dictionary
from gensim.models import LdaModel
def train_model_lda_gensim():
# 把文章转成list
common_dictionary = Dictionary(common_texts)
print(type(common_texts))
print(common_texts[0])
# 把文本转成词袋形式
common_corpus = [common_dictionary.doc2bow(text) for text in common_texts]
# 调用lda模型,并指定10个主题
lda = LdaModel(common_corpus, num_topics=10)
# 检查结果
lda.print_topic(1, topn=2)
补充: 还可以对之前生成的lda模型用新语料库去更新
# 用新语料库去更新
# 能更新全部参数
lda.update(other_corpus)
#还能单独更新主题分布, 输入为之前的参数,其中rho指学习率
lda.update_alpha(gammat, rho)
#还能单独更新词分布
lda.update_eta(lambdat, rho)
完整代码见github