特征工程(9)TF-IDF

一、TF-IDF

https://blog.csdn.net/u010417185/article/details/87905899

TF-IDF(Term Frequency-Inverse Document Frequency, 词频-逆文件频率)是一种用于资讯检索与资讯探勘的常用加权技术。TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。

上述引用总结就是, 一个词语在一篇文章中出现次数越多, 同时在所有文档中出现次数越少, 越能够代表该文章。这也就是TF-IDF的含义。

1.1 TF

TF(Term Frequency,词频)表示词条在文本中出现的频率,这个数字通常会被归一化(一般是词频除以文章总词 数), 以防止它偏向长的文件(同一个词语在长文件里可能会比短文件有更高的词频, 而不管该词语重要与否)。TF 用公式表示如下: \[ T F_{i, j}=\frac{n_{i, j}}{\sum_k n_{k, j}} \] 其中, \(n_{i, j}\) 表示词条 \(t_i\) 在文档 \(d_j\) 中出现的次数, \(T F_{i, j}\) 就是表示词条 \(t_i\) 在文档 \(d_j\) 中出现的频率。

但是, 需要注意, 一些通用的词语对于主题并没有太大的作用, 反倒是一些出现频率较少的词才能够表达文章的主题, 所以单纯使用是TF不合适的。权重的设计必须满足:一个词预测主题的能力越强, 权重越大, 反之, 权重 越小。所有统计的文章中, 一些词只是在其中很少几篇文章中出现, 那么这样的词对文章的主题的作用很大, 这些 词的权重应该设计的较大。IDF就是在完成这样的工作。

1.2 IDF

IDF(Inverse Document Frequency,逆文件频率)表示关键词的普遍程度。如果包含词条 \(i\) 的文档越少, IDF越 大, 则说明该词条具有很好的类别区分能力。某一特定词语的IDF, 可以由总文件数目除以包含该词语之文件的数 目, 再将得到的商取对数得到: \[ I D F_i=\log \frac{|D|}{1+\left|j: t_i \in d_j\right|} \] 其中, \(|D|\) 表示所有文档的数量, \(\left|j: t_i \in d_j\right|\) 表示包含词条 \(t_i\) 的文档数量, 为什么这里要加 1 呢? 主要是防止包含词条 \(t_i\) 的数量为 0 从而导致运算出错的现象发生

某一特定文件内的高词语频率, 以及该词语在整个文件集合中的低文件频率, 可以产生出高权重的TF-IDF。因此, TF-IDF倾向于过滤淖常见的词语, 保留重要的词语, 表达为 \[ T F-I D F=T F \cdot I D F \] 最后在计算完文档中每个字符的tfidf之后, 对其进行归一化, 将值保留在0-1之间, 并保存成稀疏矩阵。

二、TF-IDF Q&A

1、究竟应该是对整个语料库进行tf-idf呢?还是先对训练集进行tf-idf,然后再对xtest进行tf-idf呢?两者有什么区别?

fit
  • 学习输入的数据有多少个不同的单词,以及每个单词的idf
transform 训练集
  • 回我们一个document-term matrix.
transform 测试集

transform的过程也很让人好奇。要知道,他是将测试集的数据中的文档数量纳入进来,重新计算每个词的idf呢,还是直接用训练集学习到的idf去计算测试集里面每一个tf-idf呢?

如果纳入了测试集新词,就等于预先知道测试集中有什么词,影响了idf的权重。这样预知未来的行为,会导致算法丧失了泛化性。

2、TF-IDF 模型加载太慢

https://thiagomarzagao.com/2015/12/08/saving-TfidfVectorizer-without-pickles/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import scipy.sparse as sp
from idfs import idfs # numpy array with our pre-computed idfs
from sklearn.feature_extraction.text import TfidfVectorizer

# subclass TfidfVectorizer
class MyVectorizer(TfidfVectorizer):
# plug our pre-computed IDFs
TfidfVectorizer.idf_ = idfs

# instantiate vectorizer
vectorizer = MyVectorizer(lowercase = False,
min_df = 2,
norm = 'l2',
smooth_idf = True)

# plug _tfidf._idf_diag
vectorizer._tfidf._idf_diag = sp.spdiags(idfs,
diags = 0,
m = len(idfs),
n = len(idfs))