当前位置: 首页 > 科技观察

向量化和HashTrick在文本挖掘预处理中的体现

时间:2023-03-14 12:27:24 科技观察

前言在(文本挖掘分词原理)中,我们讲到了文本挖掘预处理的关键步骤:“分词”,而在进行分词之后,如果我们在进行文本挖掘分类和聚类,那么关键的特征预处理步骤包括向量化或向量化HashTrick的特例。在本文中,我们将总结向量化的预处理方法和特例HashTrick。BagofWords模型在我们谈论向量化和HashTrick之前,让我们先谈谈BagofWords(简称BoW)。词袋模型假设我们不考虑文本中单词之间的上下文关系,而只考虑所有单词的权重。权重与单词在文本中出现的频率有关。词袋模型首先会进行分词。分词后,通过统计每个词在文本中出现的次数,可以得到文本的基于词的特征。如果把这些词和每个文本样本对应的词频放在一起,也就是我们常说的向量化。向量化完成后,一般使用TF-IDF对特征进行权值校正,然后对特征进行标准化。经过一些其他的特征工程之后,数据可以被带入机器学习算法中进行分类和聚类。词袋模型三部曲:分词(tokenizing);统计修正词特征值(计数);规范化(normalizing);与词袋模型非常相似的一个模型是词集模型(SetofWords,简称SoW),而与词袋模型最大的区别在于它只考虑词是否出现在文本中,而不考虑词频.也就是说,一个词在文本中出现一次和在文本中出现多次的特征处理是一样的。大多数时候,我们使用的是词袋模型,下面的讨论也是基于词袋模型。当然,词袋模型有很大的局限性,因为它只考虑了词频,没有考虑上下文,所以会丢失一部分文本的语义。但大多数时候,如果我们的目的是分类聚类,词袋模型的表现会很好。BoW的向量化是在统计词袋模型的词频的步骤。我们将获得文本中所有单词的词频。有了词频,我们就可以用词向量来表示文本了。这里我们举个例子。例子直接用scikit-learn的CountVectorizer类完成。这个类可以帮助我们完成词频统计和文本的向量化。代码如下:fromsklearn.feature_extraction.textimportCountVectorizercorpus=["IcometoChinatotravel","ThisisacarpoluparinChina","IloveteaandApple","Theworkistowritesomepapersinscience"]printvectorizer.fit_transform(corpus)我们看上面4个文本的处理输出如下:(0,16)1(0,3)1(0,15)2(0,4)1(1,5)1(1,9)1(1,2)1(1,6)1(1,14)1(1,3)1(2,1)1(2,0)1(2,12)1(2,7)1(3,10)1(3,8)1(3,11)1(3,18)1(3,17)1(3,13)1(3,5)1(3,6)1(3,15)1可以看出4个文本的词频有被计算在内。输出中,左边括号中的第一个数字是文本的序号,第二个数字是词的序号,注意词的序号是基于所有文档的。第三个数字是我们的词频。我们可以进一步查看每个文本的词向量特征以及每个特征所代表的词。代码如下:printvectorizer.fit_transform(corpus).toarray()printvectorizer.get_feature_names()输出结果如下:[[0001100000000002100][0011011001000010000][1100000100001000000][0000011010110101010][0000011010110101011]',u'car',u'china',u'come',u'in',u'is',u'love',u'papers',u'polupar',u'science',u'some',u'tea',u'the',u'this',u'to',u'travel',u'work',u'write']可以看出我们一共有19个词,所以这四个文本都是19维的特征向量。每个维度的向量依次对应后面的19个词。另外,由于“I”这个词在英语中是停用词,所以不参与词频统计。由于大部分文本只会使用词汇表中的一小部分单词,因此我们的单词向量会有很多零。也就是说,词向量是稀疏的。在实际应用中,一般采用稀疏矩阵进行存储。在统计文本的词频后,我们通常使用TF-IDF来修正词特征值。矢量化的方法非常好用,也很直接,但在某些场景下很难使用。比如分词后的词汇量非常大,达到100万+。这时候如果我们直接使用向量化的方式,将对应的样本对应的特征矩阵加载到内存中,可能会爆内存。遇到这种情况,我们该怎么办?第一反应是我们要对特征进行降维,没错!而HashTrick是一种非常常用的文本特征降维方法。在HashTrick的大规模文本处理中,由于特征的维度对应着分词词表的大小,所以维度可能会非常恐怖。这时候就需要降维,不能直接使用上一节的向量化方法。最常用的文本降维方法是HashTrick。说起Hash,一点都不神秘,学过数据结构的同学都知道。这里Hash的意思也类似。在HashTrick中,我们将定义一个特征哈希对应的哈希表的大小。这个哈希表的维度会比我们词汇表的特征维度小很多,所以可以看成是降维。具体方法是,对应任意一个特征名,我们会使用Hash函数找到对应哈希表的位置,然后将特征名对应的词频统计值添加到哈希表的位置。如果用数学语言来表达,如果哈希函数h使得第i个特征被哈希到位置j,即h(i)=j,那么第i个原始特征的词频值?(i)将被散列的第j个特征的词频值是?ˉ,也就是,但是上面的方法有问题。有可能是两个原始特征的哈希位置加在一起导致词频累积特征值突然变大。为了解决这个问题,一种hashTrick的变体是signedhashtrick。这时候除了hash函数h之外,我们多了一个hash函数:这样做的好处是hash后的特征仍然是无偏估计,不会造成某些hashposition的值过大。在scikit-learn的HashingVectorizer类中,实现了一种基于signedhashtrick的算法。这里我们使用HashingVectorizer来练习HashTrick。为了简单起见,我们使用上面的19维词汇和hash将维度降为6维。当然,在实际应用中,19维数据根本不需要HashTrick。这里只是一个演示。代码如下:fromsklearn.feature_extraction.textimportHashingVectorizervectorizer2=HashingVectorizer(n_features=6,norm=None)printvectorizer2.fit_transform(corpus)输出如下:(0,1)2.0(0,2)-1.0(0,4)1.0(0,5)-1.0(1,0)1.0(1,1)1.0(1,2)-1.0(1,5)-1.0(2,0)2.0(2,5)-2.0(3,0)0.0(3,1)4.0(3,2)-1.0(3,3)1.0(3,5)-1.0类似于PCA,我们不再知道Hash后的特征名称和特征含义技巧降维。这时候我们无法像上一节向量化那样知道每一列的含义,所以HashTrick的解释性不强。小结在特征预处理中,什么时候用广义向量化,什么时候用HashTrick?标准也很简单。一般来说,只要不是词汇表的特点太大,大到内存不够用,用一般意义上的向量化肯定更好。因为向量化方法的可解释性很强,我们知道每个维度特征对应的是哪个单词,然后我们可以使用TF-IDF修改每个单词特征的权重,进一步提高特征的表示。然而,HashTrick使用了大规模的机器学习。这时候我们的词汇量很大,内存不够用向量化的方法。但是HashTrick的降维速度非常快,降维后的特征还是可以帮助我们完成后续的分类。和聚类工作。当然,由于分布式计算框架的存在,其实一般我们不会出现内存不足的情况。因此,在实际工作中,我使用特征向量化。