文本预处理:TF-IDF

前一篇博客已经讲了向量化,那么向量化之后一般都伴随着TF-IDF的处理,这篇博客就TF-IDF做一个解释。

1 向量化特征的不足

还是上一篇博客中的例子,如果我们直接将统计词频后的9{9}维向量作为文本分类的输入,会发现一些问题。比如第一个文本This is the first document.{'This\ is\ the\ first\ document.'},每个词在该文本中都只出现了一次,似乎看起来很平等,但是,像is{is}the{the}这种特征非常普遍,几乎每个样本都会出现,经常出现的词说明它是烂大街的了,并不那么重要,不能和first{first}document{document}等这种实义词混为一谈。我们的向量化特征仅仅用词频表示不了这种语义特征(语义信息),因此我们需要进一步的预处理来反映文本(词)的重要性,这就引出了TFIDF{TF-IDF}

2 TF-IDF

TF-IDF,全名:Term Frequency - Inverse Document Frequency,即“词频-逆文本频率”,由两部分组成:TF{TF}IDF{IDF}
TF{TF}就是我们说的词频,之前做的向量化已经做了文本中各个词的出现频率统计,并作为文本特征。词频tf{tf}等于词w{w}在文档(或者一段文本)d{d}中出现的次数count(w,d){count(w,d)}和文档d{d}中总词数size(d){size(d)}的比值。
tf(w,d)=count(w,d)size(d){tf(w,d)=\frac{count(w,d)}{size(d)}}
关键是IDF{IDF}怎么计算,即“逆文档频率”怎么理解。其实IDF{IDF}是帮助我们来反应一个词的重要程度的,这也是它修正仅仅用词频表示的特征值的原因和目的。如果一个词在所有文本中都出现了,那么它的IDF{IDF}值应该低,说明这个词属于烂大街的,比如the{''the''}这个单词,而反过来,如果一个词在比较少的文本中出现,那么它的IDF{IDF}值应该高,比如first{''first''}third{''third''}。这是在定性上说明IDF{IDF}的作用,那么如何从定量上分析一个词的IDF{IDF}呢?这里给出公式:
IDF(x)=logNN(x){IDF(x)=log\frac{N}{N(x)}}
其中,N{N}代表语料库中文本的总数,而N(x){N(x)}代表语料库中包含词x{x}的文本总数。但是这个公式在一些特殊情况下会有一些小问题,比如生僻词在语料库中没有,这样分母就为0{0}了,肯定不行吧。所以常常需要做一些平滑处理,使语料库中没有出现的词也可以得到一个合适的IDF{IDF}值。平滑的方法由很多种。这里我介绍在sklearn.featureextraction.text{sklearn.feature_extraction.text}TfidfVectorizer{TfidfVectorizer}TfidfTransformer{TfidfTransformer}类中用到的IDF{IDF}计算方法。
使用TfidfTransformer{TfidfTransformer}的默认参数的话,即:

TfidfTransformer(norm='l2', use_idf=True, smooth_idf=True, sublinear_tf=False)

词频tf{tf}用在了idf{idf}的计算公式中,如下:
idf(t)=log1+nd1+df(d,t)+1{idf(t)=log\frac{1+n_d}{1+{df(d,t)}}+1},(注意:参数smooth_idf=True
其中,nd{n_d}表示文档总数量,df(d,t){\text{df}(d,t) }表示包含词t{t}的文档数量。再经过tf-idf(t,d)=tf(t,d)×idf(t){\text{tf-idf(t,d)}=\text{tf(t,d)} \times \text{idf(t)}},计算出来的结果tfidf{tf-idf}向量还要做欧几里得范数(theEuclideannorm{the Euclidean norm})的标准化处理,即:vnorm=vv2=vv12+v22++vn2{v_{norm} = \frac{v}{||v||_2} = \frac{v}{\sqrt{v{_1}^2 + v{_2}^2 + \dots + v{_n}^2}}}
当参数smooth_idf=False时,idf{idf}的计算公式为:
idf(t)=lognddf(d,t)+1{\text{idf}(t) = log{\frac{n_d}{\text{df}(d,t)}} + 1}。写到这儿可能读者有点晕了,下面我们重新整理一下思路。

3 使用scikit-learn进行TF-IDF预处理

scikitlearn{scikit-learn}中,有两种方法进行TFIDF{TF-IDF}的预处理。

  • 第一种:在用CounVectorizer{CounVectorizer}类向量化之后,调用TfidfTransformer{TfidfTransformer}类进行预处理。
  • 第二种:直接调用TfidfVectorizer{TfidfVectorizer}完成向量化和TFIDF{TF-IDF}的预处理。

第一种:CounVectorizer{CounVectorizer}+TfidfTransformer{TfidfTransformer}的组合

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer

corpus = [
    'This is the first document.',
    'This is the second second document.',
    'And the third one.',
    'Is this the first document?',
]

vectorizer = CountVectorizer()
transformer = TfidfTransformer()
tfidf = transformer.fit_transform(vectorizer.fit_transform(corpus))
print(tfidf)

输出各个文本各个词的TF-IDF值如下:

  (0, 8)	0.4387767428592343
  (0, 6)	0.35872873824808993
  (0, 3)	0.4387767428592343
  (0, 2)	0.5419765697264572
  (0, 1)	0.4387767428592343
  (1, 8)	0.2723014675233404
  (1, 6)	0.22262429232510395
  (1, 5)	0.8532257361452786
  (1, 3)	0.2723014675233404
  (1, 1)	0.2723014675233404
  (2, 7)	0.5528053199908667
  (2, 6)	0.2884767487500274
  (2, 4)	0.5528053199908667
  (2, 0)	0.5528053199908667
  (3, 8)	0.4387767428592343
  (3, 6)	0.35872873824808993
  (3, 3)	0.4387767428592343
  (3, 2)	0.5419765697264572
  (3, 1)	0.4387767428592343

第二种:直接调用TfidfVectorizer{TfidfVectorizer}

from sklearn.feature_extraction.text import TfidfVectorizer
tfidf2 = TfidfVectorizer()
print(tfidf2.fit_transform(corpus))

输出的各个文本各个词的TF-IDF值和第一种方法的输出完全相同:

  (0, 8)	0.4387767428592343
  (0, 3)	0.4387767428592343
  (0, 6)	0.35872873824808993
  (0, 2)	0.5419765697264572
  (0, 1)	0.4387767428592343
  (1, 8)	0.27230146752334033
  (1, 3)	0.27230146752334033
  (1, 6)	0.2226242923251039
  (1, 1)	0.27230146752334033
  (1, 5)	0.8532257361452784
  (2, 6)	0.2884767487500274
  (2, 0)	0.5528053199908667
  (2, 7)	0.5528053199908667
  (2, 4)	0.5528053199908667
  (3, 8)	0.4387767428592343
  (3, 3)	0.4387767428592343
  (3, 6)	0.35872873824808993
  (3, 2)	0.5419765697264572
  (3, 1)	0.4387767428592343

第二种方法简洁,一步到位完成向量化,TF-IDF与标准化,推荐使用。

小结

TF-IDF是非常常用的文本预处理基本步骤,但是如果预处理中使用了Hash Trick,一般就无法使用TF-IDF了,因为Hash Trick后我们无法得到哈希后的各特征的IDF值。使用TF-IDF并标准化后,我们就可以使用各个文本的词特征向量作为文本的特征,进行分类或者聚类分析了。

==========================================

;