1 TF-IDF原理
TF-IDF原理在另一篇博客:关键词抽取模型 已经提及,这里不在重复。
2 文本矩阵化
笔者理解的文本矩阵化,即将文本进行“词向量化”。这里简述常见的语言表示模型(词嵌入、句表示、篇章表示)。
词向量类型:1)一个词一列向量的表示方法有Hash算法和word2vec。hash算法将词打散成(01010101)的数值,word2vec则同时打散定义成了向量。word2vec考虑了上下语义,doc2vec还考虑了上下语句顺序,用在段落中较好。
2)一个词一个值,bow算法+词权重,LDA主题-词语矩阵,两者有递进关系,bow进化到LDA。
根据词向量组成句向量的方式:1)一次一列向量,一般用简单相加来求得;2)一个词一个值是用权重组合成向量的方式。(谷歌的句向量sen2vec可以直接将句子变成一列向量)
词向量的额外效果:1)消除歧义:LDA的主题-词语向量;2)结合上下文语境:word2vec;3)文档与文档之间的关系:bow+TFIDF(TF-IDF能够较好区分文档差别的指标,而互信息较为有利于文档中核心词的提取)
2.1 Bow算法衍生——one-hot representation
1)词频做向量值
Bag-of-words model:该模型忽略掉文本的语法和语序等要素,将其仅仅看作是若干个词汇的集合,文档中每个单词的出现都是独立的。BOW使用一组无序的单词(words)来表达一段文字或一个文档。
举例:文档1:John likes to watch movies. <ary likes too.
文档2: John also likes to watch football games.
基于上述两个文档中出现的单词,构建如下的一个字典:
{"John": 1, "likes": 2,"to": 3, "watch": 4, "movies": 5,"also": 6, "football": 7, "games": 8,"Mary": 9, "too": 10}
上面的词典中包含10个单词, 每个单词有唯一的索引, 那么每个文本我们可以使用一个10维的向量来表示。如下:
[1, 2, 1, 1, 1, 0, 0, 0, 1, 1]
[1, 1,1, 1, 0, 1, 1, 1, 0, 0]
该向量与原来文本中单词出现的顺序没有关系,而是词典中每个单词在文本中出现的频率。
Distributed Representation是一个稠密、低维的实数限量,它的每一维表示词语的一个潜在特征,该特征捕获了有用的句法和语义特征。其特点是将词语的不同句法和语义特征分布到它的每一个维度上去表示。
2)词权重做向量值(TFIDF/CHI/MI)
TFIDF等term weighting来当做词向量。会搭配着BOW模型使用,比如先定位了每句话出现的词,然后填上的不是频数,而是每个词的向量。
2.2 Hash算法衍生——simhash算法——onehot representation(见参考链接1)
2.3 Word2Vec词向量延伸
1)word2vec
word2vec基于上下文语境来获取词向量。如图:
2)句向量
最直观的思路,对于phrase和sentence,我们将组成它们的所有word对应的词向量加起来,作为短语向量,句向量
2.4 主题模型中的topic-word向量(可参考:关键词抽取模型)
主题模型建立之后,会得到两个矩阵,一个是主题-词语向量矩阵;一个是文档-主题向量矩阵。其中的主题-词语矩阵,可以用来代表每个词。实际上,其是代表每个词在每个主题下的频率,但是作为潜在语义的判别也十分有效,业界会开发使用,来作为了解文档词语相关性的判别。
这个概率公式可以用矩阵表示:
其中”文档-词语”矩阵表示每个文档中每个单词的词频,即出现的概率;”主题-词语”矩阵表示每个主题中每个单词的出现概率;”文档-主题”矩阵表示每个文档中每个主题出现的概率。
2.5 Bog-of-word model:TF-IDF特征值为权重实现
采用sklearn中的TfidfVectorizer直接实现,TF-IDF特征值,demo如下:
from sklearn.feature_extraction.text import TfidfVectorizer
# 导入文本
corpus = ['this is the first document',
'this is the second second document',
'and the third one',
'is this the first document']
tfidf_vec = TfidfVectorizer()
tfidf_matrix = tfidf_vec.fit_transform(corpus)
# 得到语料库所有不重复的词
print(tfidf_vec.get_feature_names())
# 得到每个单词对应的id值
print(tfidf_vec.vocabulary_)
# 得到每个句子所对应的向量
# 向量里数字的顺序是按照词语的id顺序来的
print(tfidf_matrix.toarray())
3 互信息原理
互信息:是体现两个或者多个元素之间的依赖关系。以两个元素为例,互信息计算公式为:
其中:
:表示元素X与元素Y共同出现的概率;
:表示元素X单独出现的概率;
:表示元素Y单独出现的概率;
信息熵:是用来描述一个变量的确定性的,如果一个变量的确定性高,那么它的信息熵越小,反之越大。
(可参考资料:sklearn:点互信息和互信息)
4 特征筛选
特征筛选常见方法:过滤(Filter)、相关系数(Correlation coefficient)、嵌入法(Embedding)
过滤(Filter)
过滤法只用来检验特征向量和目标(响应变量)的相关度,不需要任何的机器学习算法,不依赖于任何模型,只是应用于统计量做筛选:我们根据统计量的大小,设置合适的阈值,将低于阈值的特征剔除。
相关系数(Correlation coefficient)
随机变量的方差度量的是变量的变异程度,而两个随机变量的协方差(Covariance)度量的是它们联合变异程度。如果X、Y是分别具有期望:的随机变量,那么它们的协方差定义为:
可以看出,协方差就是X与其均值偏离程度和Y与其均值偏离程度的乘积平均值。
即,如果X大于其均值,Y也倾向于大于其均值,那么协方差就为正,表明关联是正向的;如果X大于其均值,Y倾向于小于其均值,那么协方差就为负,表明关联是负向的。我们可以将其展开:
如果X和Y相互独立,那么:
(反之未必成立)
相关系数定义为:
对应的正是:
相关系数不仅在几何上更为直观,而且将相关度的测量无量纲化,相关度不再依赖于测量单位。一般情况下,根据特征对应的相关系数进行筛选特侦。
包裹(Warpper)
与过滤法不同的是,包裹法采用的是特征搜索的办法。它的基本思路是,从初始特征集合中不断的选择子集合,根据学习器的性能来对子集进行评价,直到选择出最佳的子集。在搜索过程中,我们会对每个子集做建模和训练。
上图为包裹法的流程图,其中Estimated Accuracy是机器学习分类问题的典型的性能指标。
基于此,包裹法很大程度上变成了一个计算机问题:在特征子集的搜索问题(subset search)。常见方法:前向搜索(Forward search)、后向搜索(Backward search)、双向搜索(Bidirectional search)、递归剔除(Recursive elimination)
1)前向搜索(Forward search)
在开始时,按照特征数来划分子集,每个子集只有一个特征,对每个子集进行评价。然后在最优的子集上逐步增加特征,使模型性能提升最大,直到增加特征并不能使模型性能提升为止。
2)后向搜索(Backward search)
在开始时,将特征集合分别减去一个特征作为子集,每个子集有N-1个特征。对每个特征进行评价。然后在最优的子集上逐步减少特征。使得模型性能提升最大,直到减少特征并不能使模型性能提升为止。
3)双向搜索(Bidirectional search)
将Forward search 和Backward search结合起来
4)递归剔除(Recursive elimination)
反复的训练模型,并剔除每次的最优或者最差的特征,将剔除完毕的特征集进入下一轮训练,直到所有的特征被剔除,被剔除的顺序度量了特征的重要程度。
嵌入法(Embedding)
如果仔细思考前两种方法,过滤法与学习器没有关系,特征选择只是用统计量做筛选,而包裹法则固定来了学习器,特征选择只是在特征空间上进行搜索。而嵌入法最大的突破在于,特征选择会在学习器的训练过程中自动完成。
在降低过拟合的理论中,Ridge Regression和LASSO:
它们实际上并没有改变本身的模型,只是在优化函数(均方误差)的基础上添加参数的范数,参数:的大小反映了正则项与均方误差的相对重要性,越大,正则项的权重越大,优化参数的结果就会偏好更小的参数值。
实际上,它们是通过降低权重系数的办法来降低过拟合,那么在线性模型中,降低权重系数就意味着与之相关的特征并不重要,实际上就是对特征做了一定的筛选。
其中国LASSO的方法可以将某些权重系数将为零,这意味着,只有权重系数不为零的特征才会出现在模型中。换言之,基于,正则化的方法就是一种标准的嵌入法。
图为LASSO优化结果示意,均方误差项加了正则项的效果就是:整体的优化结果不会迭代到黑点(终点),而是迭代到它们的交点,而且交点万网在轴上。
除此之外,决策树也是典型的嵌入法。因为决策树是利用一个特征进行分类,我们在生成决策树的过程就是挑选特征的过程,并且根据特征的不同取值构建子节点,直到特征没有分类能力或者很小,就停止生成节点。
利用互信息进行特征筛选
根据互信息的计算公式,即是需要计算特征与因变量之间的互信息,设置互信息阈值大小进行筛选特征或者根据互信息的结果排序,取特征。
1)相关系数法:直接计算特征与因变量一一的互信息
对于文本内容,我们在将其进行TF-IDF后,得到的矩阵是(样本数目,特征数目)。这里简单计算因变量label与特征之间一一的关系,尝试用互信息来表示,其代码如下:
# 以cnews.test.txt为例
# 读取文本
path = './cnews.test.txt'
with open(path,'r',encoding='UTF-8') as f:
cnews_test = f.readlines()
# 将test中的label取出
test_label,test_x = [],[]
for each in cnews_test:
each0 = each.split('\t')
test_label.append(each0[0])
test_x.append(each0[1])
# 载入停用词字典,对其进行去停用词
with open('./stopword.txt','r',encoding='UTF-8') as f:
stopwords = f.readlines()
a = ''
for each in stopwords:
a = a + ' '+each
stopwords = a.replace('\n','').split(' ')
stopwords = [each for each in stopwords if each not in ['\n','']]
import jieba
# 使用jieba精确分词
test_x = [[each0 for each0 in jieba.cut(each) if each0 not in stopwords] for each in test_x]
# test_x有10000个样本,取500:1500之间的1000个样本为例子
test_x1 = test_x[500:1500]
# 因为test_x1存放的是单个词语构成的list,现在将其按照' '将其为字符串形式
test_x1 = [' '.join(each) for each in test_x1]
from sklearn.feature_extraction.text import TfidfVectorizer
tfidf_vec = TfidfVectorizer(ngram_range=(1,2),min_df=0.2, max_df=0.9,use_idf=1,smooth_idf=1, sublinear_tf=1)#
# 参数:ngram_range=(1,2)可理解为滑窗,设置(1,2),意思是取临近的两个词语计算;min_df=0.2,max_df=0.9,表示只取词频率在0.1-0.9的词语
# 之所以设置了这一部,主要为降低经过TF-IDF后的维数或者特征
tfidf_matrix = tfidf_vec.fit_transform(test_x1)
X_matrix = tfidf_matrix.toarray()
# 将test中前1000个样本中的label取出
X_label = test_label[500:1500]
# 将label值转换为数值类型
char2num = dict(zip(list(set(X_label)),range(len(set(X_label)))))
X_labelnum = []
for each in X_label:
X_labelnum.append(char2num[each])
# 现计算样本label与样本特征之间一一的互信息
X_matrix_T = X_matrix.T
X_MI = {} # 用于存储X_matrix特征与label之间的互信息值
from sklearn import metrics as mr
import numpy as np
X_labels = np.array(X_labelnum)
for i in range(X_matrix_T.shape[0]):
X_MI[i] = mr.mutual_info_score(X_labels,X_matrix_T[i])
# 筛选特征,根据互信息的大小进行从大到小排序,留下前20的特征
X_MIF = [each for each in X_MI if X_MI[each]>=sorted(X_MI.values())[10]]
print('选择的特征对应列序号:',X_MIF)
X_fea = [X_matrix[each] for each in X_MIF]
X_matrix_fea = np.array(X_fea).T
# 运行结果:选择的特征对应列序号: [0, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 24, 25, 28, 29, 30, 31, 32, 33, 34, 35, 36, 38]
上述代码操作结果见:文本TF-IDF并计算MI
2)包裹法:选择一个机器学习方法,将特征组合成得不同特征子集放入机器学习方法中训练并预测得到label值,然后将预测得到的label_pred与真实的label_true进行计算互信息,再自定义选择规则,选择出合适的特征。这里的特征组合可以根据前面提到的前向算法、后向算法、双向算法、递归剔除等方法进行。
3)嵌入法:将所有特征放入一个模型中,利用优化函数,不停计算特征的权重值的过程就是在选择特征的过程,与前面不一样的是,这里的特征选择过程中并不会如前面两种方法会直接不要某个特征,只是降低了某个特征的权重值,当然若权重为0就相当于舍弃了这个特征了。
参考资料:
链接1:自然语言处理︱简述四大类文本分析中的“词向量”(文本词特征提取)
链接2:使用不同的方法计算TF-IDF值
链接3:文本向量空间模型
链接4:sklearn:点互信息和互信息