文本数据处理
文本数据处理常见任务
- 文本分类
文本分类是按照一定的分类体系,将文档判别为预定的若干类中的某一类或某几类。- 信息检索
指将信息(此处指代文本)按一定的方式组织起来,根据用户的需求将相关信息查找出来- 信息抽取
将文本中包含的结构化或非结构化的信息抽取出来,组成类似表格的形式- 自动问答
用准确、简洁的自然语言回答用户以文本形式提出的问题- 机器翻译
一种自然语言文本自动转换为另一种自然语言文本- 自动摘要
从一份或多份文本中提取出来部分文字,它包含了原文本中的重要信息,且长度不超过或远小于原文本的一半
文本处理的基本步骤
Step1:文本采集
文本提取与整理
Step2:文本预处理
文本分词、去停用词、词性标注、样本标注
Step3:特征选择—>特征提取
Step4:建模分析(分类模型、CRF模型、RNN模型、LSTM模型)
文本预处理—中文分词
- 词:最小的能够独立活动的有意义的语言成分
英文单词之间以空格分界
汉语以字为基本书写单位,词语之间没有明确的区分- 分词
将连续的字序列按照一定的规范重新组合成词序列
Python分词库:jieiba库
- 精确模式:将句子最精确地且分开,适合文本分析
- 搜索引擎模式:在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词
- 全模式:把句子中所有的可以成词的词语都扫描出来,速度快但不能解决歧义。
jieba中文分词函数:
函数 | 参数说明 |
---|---|
lcut(sentence, cut_all= False, HMM= True) | sentence:待分词的字符串;cut_all:是否采用全模式;HMM:是否使用HMM模型。直接返回词列表。适用于精确模式和全模式 |
lcut_for_search (sentence, HMM= True) | sentence:待分词的字符串;HMM:是否使用 HMM 模型。直接返回词列表 |
cut(sentence, cut_all= False, HMM= True) | 等同于lcut()函数,但不会直接返回词列表,返回的是可迭代的generator。若想直接返回词列表,则需要做其他操作 |
cut_for_search (sentence, HMM= True) | 等同于lcut_for_search()函数,但不会直接返回词列表,返回的是可迭代的generator。若想直接返回词列表,则需要做其他操作 |
详见例题6-1 |
例题6-1:将文本句子 “2018年世界杯小组赛抽签在莫斯科克里姆林宫举行”进行分词
'''方式一:利用lcut()和lcut_for_search()函数'''
import jieba
print("精确模式切分为:\n",jieba.lcut("2018年世界杯小组赛抽签在莫斯科克里姆林宫据举行"))
print("搜索引擎模式切分为:\n",jieba.lcut_for_search("2018年世界杯小组赛抽签在莫斯科克里姆林宫据举行"))
print("全模式切分为:\n",jieba.lcut("2018年世界杯小组赛抽签在莫斯科克里姆林宫据举行",cut_all= True))
'''方式二:利用cut()和cut_for_search()函数,此处仅以精确模式为例'''
import jieba
words= jieba.cut_for_search("2018年世界杯小组赛抽签在莫斯科克里姆林宫据举行")
print(words)
for word in words:
print(word)
文本预处理—词性标注
jieba库的posseg模块提供词性标注
from jieba import posseg as pseg
pseg.lcut()
或pseg.lcut_for_search()
等同于pseg.cut
或pseg.cut_for_search()
- 词性:如名词、动词、形容词、代词等
利用cut()或cut_for_search()函数
from jieba import posseg as pseg
words= pseg.cut("2018年世界杯小组赛抽签在莫斯科克里姆林宫据举行")
for word, tag in words:
print("word:{}, tag:{}".format(word, tag))
利用lcut()或lcut_for_search()函数
方式一:
from jieba import posseg as pseg
pseg.lcut("2018年世界杯小组赛抽签在莫斯科克里姆林宫据举行")
方式二:
from jieba import posseg as pseg
for word,tag in pseg.lcut("2018年世界杯小组赛抽签在莫斯科克里姆林宫据举行"):
print("word:{},tag:{}".format(word,tag))
方式一:
方式二:
特征选择与特征提取
- 作用:将文本内容转换成数字特征向量
- 有三种模型可供转换:
词袋模型、TF-IDF模型、词向量模型--------本章只讲前两种模型
词袋模型
- 基本思想:
将一条文本仅看作一些独立的词语的集合,忽略文本的词序、语法和句法。
简单讲就是将每条文本都堪看成一个袋子,里面装的是词,成为词袋,分析时用词袋代表整个文本。
词袋模型统计在一个句子中每个单词出现的频数
- 词袋模型构建过程:
对文档集进行分词—>构造字典—>生成词袋向量- 词袋模型实现:
sklean库中的feature_extraction.text模块的CountVectorizer类
from sklearn.feature_extraction.text import CountVectorizer
词袋模型初始化:
cv= CountVectorizer(token_pattern, max_features)
生成词袋向量
cv_fit= cv.fit_transform(split_corpus)
生成特征列表
cv.get_feature_names()
生成特征向量
cv_fit.toarray()
参数说明如下:
例题6-2文本词袋特征生成。
from sklearn.feature_extraction.text import CountVectorizer
import jieba
'''给出文档集,放在字符串列表中'''
corpus= [
'我是中国人,我爱中国',
'我是上海人',
'我住在上海松江大学城']
'''定义字符串空列表,用来存文档集中每个字符串的词袋'''
split_corpus= []
'''初始化分词结果的列表,循环为corpus中的每个字符串分词,即对文档集进行分词'''
for c in corpus:
s= ' '.join(jieba.lcut(c))
split_corpus.append(s)
print(split_corpus)
'''生成词袋'''
'''词袋模型初始化'''
cv= CountVectorizer()
'''构造字典生成词袋向量'''
cv_fit= cv.fit_transform(split_corpus)
'''显示特征列表'''
print(cv.get_feature_names())
'''显示特征向量'''
print(cv_fit.toarray())
TF-IDF模型
- 定义:
“词频-逆文本频率”,是词袋模型的一个变种,区别是将词频值改为TF-IDF值,用于评估一个词对于一个文档的重要程度。- TF:词频
某个词在文档中出现的次数或频率
若某个词在某文档中出现多次,则说明这个词可能比较重要或者是文档常用词- IDF:逆文档频率
计算方法:将文档集中总文档数量除以包含该词语的文档数量,再将得到的商取对数。
DF主要用来取出文档常用词,如停用词的IDF值就会很低。
TF-IDF:TF和IDF乘积
作用:过滤到常见的词语,保留重要的词语。
- TF-IDF模型构建过程
对文档集进行分词—>构造字典—>生成TF-IDF向量
注意:构建过程与词袋模型一致,唯一区别:在构造字典时,将词对应的词频改为TF-IDF值
TF-IDF模型实现
方法一
sklearn库中的feature_extraction.text模块中的TfidfTransformer类。
在词袋向量的基础上TfidTransformer类完成TF-IDF计算。
from sklearn.feature_extraction.text import TfidfTransformer
TF-IDF模型初始化
tfidf= TfidfTransformer()
生成TF-IDF向量
tfidf_fit= tfidf.fit_transform(cv_fit)
—cv_fit为ConubtVectiorizer类生成的词袋向量
生成TF-IDF特征向量
tfidf_fit.toarray()
方法二
sklearn库中的feature_extraction.text模块中的TfidfVectorizer类完成向量化、TF-IDF计算。
from sklearn.feature_extraction.text import TfidfVectorizer
TF-IDF模型初始化
tfidf= TfidfVectorizer(token_pattern)
------参数与词袋模型参数一样
生成TF-IDF向量
tfidf_fit= tfidf.fit_transform(split_corpus)
生成TF-IDF特征向量
tfidf_fit.toarray()
方法一:feature_extraction.text模块的TfidfTransformer类
import jieba
'''给出文档集,放在字符串列表中'''
corpus= [
'我是中国人,我爱中国',
'我是上海人',
'我住在上海松江大学城']
'''定义字符串空列表,用来存文档集中每个字符串的词袋'''
split_corpus= []
'''初始化分词结果的列表,循环为corpus中的每个字符串分词,即对文档集进行分词'''
for c in corpus:
s= ' '.join(jieba.lcut(c))
split_corpus.append(s)
print(split_corpus)
'''生成词袋'''
'''词袋模型初始化'''
from sklearn.feature_extraction.text import CountVectorizer
#(?u)\b\w\w+\b为其默认参数
cv= CountVectorizer(token_pattern= r"(?u)\b\w\w+\b")
'''构造字典生成词袋向量'''
cv_fit= cv.fit_transform(split_corpus)
'''在例题6-2后加如下代码即可变为TF-IDF模型'''
from sklearn.feature_extraction.text import TfidfTransformer
'''TF-IDF模型初始化'''
tfidf_transformer= TfidfTransformer()
'''生成TF-IDF向量'''
tfidf_fit= tfidf_transformer.fit_transform(cv_fit)
'''显示TF-IDF特征向量'''
print(tfidf_fit.toarray())
方法二:直接用分词后得到的列表计算TF-IDF特征表示
import jieba
'''给出文档集,放在字符串列表中'''
corpus= [
'我是中国人,我爱中国',
'我是上海人',
'我住在上海松江大学城']
'''定义字符串空列表,用来存文档集中每个字符串的词袋'''
split_corpus= []
'''初始化分词结果的列表,循环为corpus中的每个字符串分词,即对文档集进行分词'''
for c in corpus:
s= ' '.join(jieba.lcut(c))
split_corpus.append(s)
print(split_corpus)
print('-----------------------')
from sklearn.feature_extraction.text import TfidfVectorizer
'''TF-IDF模型初始化'''
tfidf= TfidfVectorizer(token_pattern= r"(?u)\b\w\w+\b")
'''生成TF-IDF向量'''
tfidf_fit= tfidf.fit_transform(split_corpus)
'''显示特征向量'''
print(tfidf_fit.toarray())
思考与练习1
在例6-2的文档集中添加2条文本,“松江大学城有很多大学”、“大学城共有15万余大学生”。计算文档集中每条文本的词袋和TF-IDF特征表示。
方法一:feature_extraction.text模块的TfidfTransformer类
import jieba
from sklearn.feature_extraction.text import CountVectorizer,TfidfTransformer
corpus= [
'我是中国人,我爱中国',
'我是上海人',
'我住在上海松江大学城',
'松江大学城有很多大学',
'大学城共有15万余大学生']
split_corpus= []
for c in corpus:
s= " ".join(jieba.lcut(c))
split_corpus.append(s)
print("每条文本的词袋为:\n",split_corpus)
print('-------------------------------------------------------------')
from sklearn.feature_extraction.text import CountVectorizer
cv= CountVectorizer(token_pattern= r"(?u)\b\w\w+\b")
cv_fit= cv.fit_transform(split_corpus)
print("词袋模型的特征列表为:\n",cv.get_feature_names())
print("词袋模型的特征向量为:\n",cv_fit.toarray())
from sklearn.feature_extraction.text import TfidfTransformer
tfidf_transformer= TfidfTransformer()
tfidf_fit= tfidf_transformer.fit_transform(cv_fit)
'''显示TF-IDF的特征向量'''
print(tfidf_fit.toarray())
方法二:直接用分词后得到的列表计算TF-IDF特征表示
'''方式二'''
import jieba
from sklearn.feature_extraction.text import TfidfVectorizer
corpus= [
'我是中国人,我爱中国',
'我是上海人',
'我住在上海松江大学城',
'松江大学城有很多大学',
'大学城共有15万余大学生']
split_corpus= []
for c in corpus:
s= " ".join(jieba.lcut(c))
split_corpus.append(s)
print(split_corpus)
print('----------------------------------------------------------')
from sklearn.feature_extraction.text import TfidfVectorizer
tfidf= TfidfVectorizer(token_pattern= r"(?u)\b\w\w+\b")
tfidf_fit= tfidf.fit_transform(split_corpus)
'''显示TF-IDF特征向量'''
print(tfidf_fit.toarray())
垃圾邮件识别—此处利用分类算法中的SVM模型
- 垃圾邮件识别技术
关键词识别
IP黑名单
反向DNS查找
意图分析技术链接URL
分类算法(最常见)等
分类算法进行垃圾邮件识别
- 实现步骤:
收集大量的垃圾邮件和非垃圾邮件
建立垃圾邮件库和非垃圾邮件库
提取其中的特征
训练分类模型
- 使用词袋模型或TF-IDF模型提取特征
得到m*n的矩阵X。m为10000,n为文本集的字典词条数目
标签向量y长度为m,元素值为0或1
import jieba
#从文本中读取文本,放在列表中
mail= open('E:\data\mailcorpus.txt', 'r', encoding= 'utf-8')
corpus= mail.readlines()#列表中的每个元素为一行文本
split_corpus= []
for c in corpus:
s= " ".join(jieba.lcut(c))
split_corpus.append(s)
from sklearn.feature_extraction.text import CountVectorizer
cv= CountVectorizer()
X= cv.fit_transform(split_corpus).toarray()
'''
等同于:
cv_fit= cv.fit_transform(split_corpus)
X= cv_fit.toarray()
'''
#构造标签向量,垃圾标签为0,正常标签为1
y= [0]*5000+[1]*5000
#将数据集切分为训练集和测试集
from sklearn import model_selection
from sklearn import svm
from sklearn import metrics
X_train, X_test, y_train, y_test= model_selection.train_test_split(X, y, test_size= 0.4, random_state= 0)
#使用SVM训练分类器模型
#利用高斯核函数,并设置其系数为0.7,误差项的惩罚参数为1
svm= svm.SVC(kernel= 'rbf', gamma= 0.7, C= 1.0)
svm.fit(X_train, y_train)
#测试集模型预测
predicted_ytest= svm.predict(X_test)
#测试集的准确率
print("SVM accuracy:\n", svm.score(X_test, y_test))
#SVM分类性能报告
print("SVM report:\n", metrics.classification_report(y_test, predicted_ytest))
#SVM混淆矩阵计算
print("SVM matrix:\n",mean.confusion_matrix(y_test,predicted_ytest))
思考与练习2
第一题:将邮件特征提取从词袋模型改为TF-IDF模型,比较使用不同的特征计算模型的分类性能。
import jieba
mail= open('E:\data\mailcorpus.txt', 'r', encoding= 'utf-8')
corpus= mail.readlines()
split_corpus= []
for c in corpus:
s= " ".join(jieba.lcut(c))
split_corpus.append(s)
from sklearn.feature_extraction.text import TfidfVectorizer
tfidf= TfidfVectorizer(token_pattern= r"(?u)\b\w+\b")
tfidf_fit= tfidf.fit_transform(split_corpus)
X= tfidf_fit.toarray()
y= [0]*5000+[1]*5000
from sklearn import model_selection, metrics, svm
X_train, X_test, y_train, y_test= model_selection.train_test_split(X, y, test_size= 0.4, random_state= 0)
svm= svm.SVC(kernel= 'rbf', gamma= 0.7, C= 1.0)
svm.fit(X_train, y_train)
predicted_ytest= svm.predict(X_test)
print("SVM accuracy:\n",svm.score(X_test, y_test))
print("SVM report:\n",metrics.classification_report(y_test, predicted_ytest))
print("SVM matrix:\n", metrics.confusion_matrix(y_test, predicted_ytest))
第二题:使用Scikit-learn的CountVectorizer()函数初始化词袋模型时,设置不同的特征个数生成邮件的特征表示向量,比较训练分类模型所耗费的时间,以及分类模型分类的准确性。特征个数越多是否意味分类性能越好?
import jieba
from sklearn import metrics,svm,model_selection
def svmm(a,b):
X_train, X_test, y_train, y_test= model_selection.train_test_split(a, b, test_size= 0.7, random_state= 0)
svm= svm.SVC(kernel= 'rbf', gamma= 0.7, C= 1.0)
svm.fit(X_train, y_train)
predicted_ytest= svm.predict(X_train)
print("SVM accuracy:\n",svm.score(X_test, y_test))
print("SVM report:\n",metrics.classification_report(y_test, predicted_ytest))
print("SVM matrix:\n", metrics.confusion_matrix(y_test, predicted_ytest))
return
mail= open('E:\data\mailcorpus.txt', 'r', encoding= 'utf-8')
corpus= mail.readlines()
split_corpus= []
for c in corpus:
s= " ".join(jieba.lcut(c))
split_corpus.append(s)
from sklearn.feature_extraction.text import CountVectorizer
cv= CountVectorizer(token_pattern= r"(?u)\b\w+\b")
cv_fit= cv.fit_transform(split_corpus)
for i in range(500,10000,500):
X= cv_fit.toarray()[0:i]
y= [0]*i+[1]*i
svmm(X, y)