数字化运维 – PYTHON 日常数据分析 –新闻文本分类实战
文本数据载入及清洗
搜狗新闻数据源:http://www.sogou.com/labs/resource/ca.php
我们从搜狗下载的数据是类似XML的带标签对的数据,因此需要使用正则表达式或者BeautifulSoup等工具处理为dataframe格式,如下图,大家通过网络爬虫获取的数据处理方法也类似。
文本数据提取这里就不赘述了,下面直接读入处理后的csv文件
import pandas as pd
import jieba
data = pd.read_table('news_data/news_data.txt')
把数据集分为训练集和测试集
sk-learn库中train_test_split函数可以把数据集随机划分为训练集和测试集,训练集用于模型训练,测试集用于检验模型的优劣,random_state参数是指定随机种子。
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(data['新闻内容'], data['类别'], random_state=1)
中文分词
我们使用jieba库进行分词,并以空格把分词连成字符串。
def fenci(train_data):
words_df = train_data.apply(lambda x:' '.join(jieba.cut(x)))
return words_df
x_train_fenci = fenci(x_train)
x_train_fenci[:5]
分词后的数据如下:
3186 中新网 上海 6 月 1 4 日电 ( 记者 于俊 ) 今年 的 父亲节 , 人们 可 通过...
632 目前 正值 中 报 发布 之际 , 多家 券商 认为 , 上半年 银行 整体 利润 增速 下...
577 作为 中非 合作 论坛 的 重要 分 论坛 之一 , 中 非金融 合作 论坛 将 于 1 3...
2406 雅虎 体育讯 北京 时间 7 月 3 日 下午 , 炎炎夏日 中 山东 球迷 终于 迎来...
4686 欧莱雅集团 的 药妆 品牌 理肤泉 ( 右图 ) 和 薇 姿 ( 左图 ) 。 资料 图...
Name: 新闻内容, dtype: object
引入停用词
infile = open("stopwords.txt",encoding='utf-8')
stopwords_lst = infile.readlines()
stopwords = [x.strip() for x in stopwords_lst]
文本特征提取(词库表示法)
CountVectorizer旨在通过计数来将一个文档转换为向量。当不存在先验字典时,Countvectorizer作为Estimator提取词汇进行训练,并生成一个CountVectorizerModel用于存储相应的词汇向量空间。该模型产生文档关于词语的稀疏表示。下面举一个例子示范:
#用于转词向量的语料
yuliao = ['dog cat fish dog dog dog','cat eat fish','i like eat fish']
#sklearn库CountVectorizer转词向量
from sklearn.feature_extraction.text import CountVectorizer
cv = CountVectorizer()
vector = cv.fit_transform(yuliao)
vector.todense()
转换后的矩阵为
matrix([[1, 4, 0, 1, 0],
[1, 0, 1, 1, 0],
[0, 0, 1, 1, 1]], dtype=int64)
接下来我们看下提取到的特征分别是
#提取到的文本特征
cv.vocabulary_
得到的文本特征
{'cat': 0, 'dog': 1, 'eat': 2, 'fish': 3, 'like': 4}
从上面的例子可以看出,语料中每个词作为一个特征,词频数作为特征的值,如第一句中dog出现了4次,因此特征值为4。下面我们使用CountVectorizer把分词后的新闻文本转为向量。sklearn库中可以指定stopwords,我们把之前准备好的停用词表穿进去就好,这样我们的文本特征提取就做好啦。
vectorizer = CountVectorizer(stop_words=stopwords, max_features=5000)
vectorizer.fit(x_train_fenci)
机器学习建模
这里我们使用朴素贝叶斯分类器,关于朴素贝叶斯算法,刘建平的博客写得非常不错,我就不再花时间整理啦,给大家推荐一波https://www.cnblogs.com/pinard/p/6069267.html
from sklearn.naive_bayes import MultinomialNB
classifier = MultinomialNB()
#模型训练
classifier.fit(vectorizer.transform(x_train_fenci), y_train)
#使用训练好的模型进行预测
classifier.score(vectorizer.transform(fenci(x_test)), y_test)
得到的准确率为
0.80479999999999996
预测的准确率是80.5%,棒棒哒
文本特征提取(TF-IDF)
TF-IDF(term frequency–inverse document frequency),词频-逆文件频率。
是一种用于资讯检索与资讯探勘的常用加权技术。TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降
一个词语在一篇文章中出现次数越多, 同时在所有文档中出现次数越少, 越能够代表该文章.
下面直接给出一个词x的IDF的基本公式如下:
IDF(x)=lgNN(x) 其中,N代表语料库中文本的总数,而N(x)代表语料库中包含词x的文本总数
TF−IDF(x)=TF(x)∗IDF(x) 其中TF(x)指词x在当前文本中的词频
词库表示法的缺点:一些普遍出现的词,词频较高,看起来似乎是更重要的特征,但因为这个词普遍出现,这个词可能不是非常的重要。如果我们的向量化特征仅仅用词频表示就无法反应这一点。因此我们需要进一步的预处理来反应文本的这个特征,而这个预处理就是TF-IDF。
用scikit-learn进行TF-IDF预处理
from sklearn.feature_extraction.text import TfidfVectorizer
#使用tf-idf把文本转为向量
tv = TfidfVectorizer(stop_words=stopwords, max_features=5000, lowercase = False)
tv.fit(x_train_fenci)
#模型训练
classifier.fit(tv.transform(fenci(x_train)), y_train)
#利用训练好的模型测试
classifier.score(tv.transform(fenci(x_test)), y_test)
得到的准确率为
0.81599999999999995
可以看出使用TF-IDF预处理后,得到的预测准确率有了明显的提高。
TF-IDF是非常常用的文本挖掘预处理基本步骤,使用了IF-IDF并标准化以后,我们就可以使用各个文本的词特征向量作为文本的特征,进行分类或者聚类分析。
N-gram模型
在朴素贝叶斯算法中,为了避免维度灾难,有一个大胆的假设,即X的n个维度之间相互独立: P(X1=x1,X2=x2,…Xn=xn|Y=Ck)=P(X1=x1|Y=Ck)P(X2=x2|Y=Ck)…P(Xn=xn|Y=Ck) 这个假设下,条件分布大大的简化了,但是这也可能带来预测的不准确性。n个维度相互独立,就是完全没有考虑上下文语境,把每个词拆开单独看,这么看的话,猫吃鱼、鱼吃猫得到的特征向量是完全一样的。
N-gram模型就是假设$X_n$与附近n个词是相关的,比如当n=(1,2)时,猫吃鱼提取到的特征就是[‘猫’,’吃’,’鱼’,’猫吃’,’吃鱼’],为了平衡计算量和上下文关系,N一般取2或者3。朴素贝叶斯n个维度之间完全相互独立的假设,就是N-gram的n=1时的情况
#转词向量
tv_2gram = TfidfVectorizer(stop_words=stopwords, max_features=5000, ngram_range=(1,2),lowercase = False)
tv_2gram.fit(x_train_fenci)
#训练模型
clf_2gram = MultinomialNB()
clf_2gram.fit(tv_2gram.transform(fenci(x_train)), y_train)
#预测
clf_2gram.score(tv_2gram.transform(fenci(x_test)), y_test)
得到的准确率为
0.81679999999999997
可以看出,指定N-gram模型n=2时,增加了附近2个词的关联,预测的准确率又上升了一丢丢