TF-IDF

1、背景

TF-IDF是信息检索和文本挖掘中常用的特征加权技术,同样常用于文本主题提取和分词加权等场景。

TF-IDF是一种完全基于统计的方法,其核心思想是假设字词的重要性与其在某篇文章中出现的比例成正比,与其在其他文章中出现的比例成反比。

2、TF-IDF

怎么理解呢?某个词在一篇文章中反复出现有两种情况,即这个词是关键词或者常用词(可理解为停用词)。要确定这个词的最终属性则需要考虑这个词在其他文章中出现的频率,若其他文章出现频率高则可以判断为常用词,出现频率低则可以确定为该词所属文章的主题词。

2.1、TF

TF (Trem Frequency) 表示词频,即一个词在文章中出现的次数。实际应用中不同长度的文章中指定词出现的次数可能与文档长度有正相关,因此我们需要对词频进行归一化处理,通常用次数除以文章的总词数:
\[
tf_{ij} = \frac{n_{i,j}}{\sum_{k}n_{k,j}}
\]
公式中分子\( n_{i,j}\) 表示词语\(t_i\)在文本\(j\)中的频数,分母\(\sum_{k}n_{k,j}\)表示文档\(j\)中所有词汇量总和。

即是说:
\[
TF_w = \frac{给定词w在当前文章出现的次数}{当前文章中的总词量}
\]
\(TF\)在应用中一般是在分词的时候在线计算。

2.2、IDF

IDF(Inverse Document Frequency)表示逆文档率,定义为文件总数除以包含给定词出现的文档数。
\[
idf_{i} = log\frac{\left|D\right|}{\left|\left\{j:t_i\in d_j\right\}\right|}
\]
公式中\(\left|D\right|\)表示语料库\(d\)的文档总数,分母\(\left|\left\{j:t_i\in d_j\right\}\right|\)表示语料库\(d\)中包含文档\(j\)中词语\(t_i\)的文档数,实际应用中为了避免分母为\(0\),因此分母一般采用\(\left|1 + \left\{j:t_i\in d_j\right\}\right|\)。

即是说:
\[
IDF=log \frac{语料库文档总数}{包含词w的文档数}
\]
\(IDF\)在应用中一般是采用业务相关语料离线计算。

2.3、TF-IDF

\(TF-IDF\)定义为:
\[
TF-IDF_{i,j}\rightarrow tf_{i,j} \times idf_{i}=\frac{n_{i,j}}{\sum_{k}n_{k,j}}\times log \frac{\left|D\right|}{\left|1+\left\{j:t_{i}\in{d_{j}}\right\}\right|}
\]
以上就是TF-IDF算法的全部理论。

2.4、实现

目前很多分词框架和机器学习算法包均集成了TF-IDF算法,以下做一个简要的罗列:

2.4.1、结巴分词(Python)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2019/10/30 09:48
# @Author  : mokundong
import jieba.analyse
str = "自然语言是人类智慧的结晶,自然语言处理是人工智能中最为困难的问题之一,而对自然语言处理的研究也是充满魅力和挑战的。"
jieba.analyse.extract_tags(s, topK=10, withWeight=True, allowPOS=())

越是重要的词语所给予的权重就越大。

2.4.2、Scikit-learn

Scikit-learn提供了自己训练的模型的接口

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2019/10/30 09:48
# @Author  : mokundong
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer

x_train = ['这是 第一 篇 文章 ,',
           '这 篇 文章 是 第二 篇 文章 。',
           '这是 第三 篇 文章 。'
           ]
x_test = ['这是 第几 篇 文章 ?']
CV = CountVectorizer(max_features=10)
transformer = TfidfTransformer()
tf_idf = transformer.fit_transform(CV.fit_transform(x_train))
x_train_weight = tf_idf.toarray()
tf_idf = transformer.transform(CV.transform(x_test))
x_test_weight = tf_idf.toarray()
print(x_test_weight)


'''
output:
[[0.61335554 0.         0.         0.         0.78980693]]
'''

2.4.3、笔者在项目中,一般采取的方法是:

a、首先用相关的文本训练IDF值保存文件;

b、在项目中首先初始化文件到内存,保存为字典便于快速查询;

c、新文档读入后实时计算TF值并查询相关IDF值计算出TF-IDF值。

2.5 总结

本质上\(IDF\)是一种试图抑制噪声的加权,单纯的以为文本频率小的单词就越重要,文本频率大的单词就越无用。这对于大部分文本信息,并不是完全正确的。\(IDF\) 的简单结构并不能使提取的关键词,十分有效地反映单词的重要程度和特征词的分布情况,使其无法很好地完成对权值调整的功能。尤其是在同类语料库中,这一方法有很大弊端,往往一些同类文本的关键词被掩盖。例如:语料库 \(D\) 中教育类文章偏多,而文本 \(j \)是一篇属于教育类的文章,那么教育类相关的词语的\( IDF \)值将会偏小,使提取文本关键词的召回率更低。因此才会有词语逆频率方式计算加权算法 \(TF-IWF\) (Term Frequency-Inverse Word Frequency),关于\(TF-IWF\)将会在下篇文章讲解。

并且,笔者在工作实践中发现针对于短句应用\(TF-IDF\)提取关键词时,由于短句中每个词的\(DF\)值往往是相同的,鉴于上述\(IDF\)天然的弱点,此算法应用于短句分析也显得不可靠,针对短句这种情况,笔者的思路是结合词性和黑白名单以及搜索点击数据和业务打tag等,需要比较综合的方式来解决短句问题。

参考文献 http://dx.doi.org/10.12677/csa.2013.31012

posted @ 2020-01-15 14:38  peacocks  阅读(870)  评论(0编辑  收藏  举报