前言

  本内容主要介绍 TF-IDF 算法,以及 Python 实现。

1.1 TF-IDF 算法的概念

  TF-IDF(Term Frequency - Inverse Document Frequency,词频-逆文档频率),是一种用于信息检索与数据挖掘的常用加权技术,常用于挖掘文章中的关键词。TF-IDF 是一种统计分析方法,用于评估一个词对一个文件集或者一个语料库的重要程度。

  TF-IDF 有两部分,TF 和 IDF,下面将进行说明。

1.1.1 TF

  TF(Term Frequency,词频),某个词在文档中出现的次数或频率。如果某篇文档中的某个词出现多次,那这个词可能是比较重要的词。当然,需要排除停用词。计算公式如下:

词 频 ( T F ) = 某 个 词 在 文 档 中 的 出 现 次 数 (1) 词频(TF)=某个词在文档中的出现次数 \tag{1} TF=(1)

  考虑到文档有长短之分,为了便于不同文档的比较,对“词频”进行标准化。计算公式如下:

词 频 ( T F ) = 某 个 词 在 文 档 中 出 现 的 次 数 / 文 档 的 总 词 数 (2) 词频(TF)= 某个词在文档中出现的次数 / 文档的总词数 \tag{2} TF=/(2)

1.1.2 IDF

  IDF(Inverse Document Frequency,逆文档频率),这是一个词语“权重”的度量,如果一个词在多篇文档中词频较低,也就表示这是一个比较少见的词,则这个词 IDF 值越大。计算公式如下:

逆 文 档 频 率 ( I D F ) = log ⁡ ( 语 料 库 的 文 档 总 数 / ( 包 含 该 词 的 文 档 数 + 1 ) ) (3) 逆文档频率(IDF)= \log(语料库的文档总数/(包含该词的文档数+1)) \tag{3} IDF=log(/(+1))(3)

  如果一个词越常见那么分母就越大,逆文档频率就越小越接近 0。分母之所以要加 1,是为了避免分母为 0(即所有文档都不包含该词),这属于一种平滑方法。

  注意:在不同的库中,实现 IDF 时,使用的平滑方法不完全相同。

1.1.3 TF-IDF

  将 TF 和 IDF 相乘就得到 TF-IDF,计算公式如下:

T F − I D F = 词 频 ( T F ) × 逆 文 档 频 率 ( I D F ) (4) TF-IDF=词频(TF)\times 逆文档频率(IDF) \tag{4} TFIDF=TF×IDF(4)

  一个词的重要程度跟它在文档中出现的次数成正比,跟它在语料库出现的次数成反比。这种计算方式能有效避免常用词对关键词的影响,提高了关键词与文章之间的相关性。

1.2 代码实现 TF-IDF 算法

1.2.1 用 Python 实现 TF-IDF 算法

使用 Python 手动实现 TF-IDF 算法,具体代码如下:

import math

class TfIdf:
    def __init__(self):
        self.num_docs = 0
        self.vocab = {}

    def add_corpus(self, corpus):
        self._merge_corpus(corpus)

        tfidf_list = []
        for sentence in corpus:
            tfidf_list.append(self.get_tfidf(sentence))
        return tfidf_list

    def _merge_corpus(self, corpus):
        """
        统计语料库,输出词表,并统计包含每个词的文档数。
        """
        self.num_docs = len(corpus)
        for sentence in corpus:
            words = sentence.strip().split()
            words = set(words)
            for word in words:
                self.vocab[word] = self.vocab.get(word, 0.0) + 1.0

    def _get_idf(self, term):
        """
        计算 IDF 值
        """
        return math.log(self.num_docs / (self.vocab.get(term, 0.0) + 1.0))

    def get_tfidf(self, sentence):
        tfidf = {}
        terms = sentence.strip().split()
        terms_set = set(terms)
        num_terms = len(terms)
        for term in terms_set:
            # 计算 TF 值
            tf = float(terms.count(term)) / num_terms
            # 计算 IDF 值,在实际实现时,可以提前将所有词的 IDF 提前计算好,然后直接使用。
            idf = self._get_idf(term)
            # 计算 TF-IDF 值
            tfidf[term] = tf * idf
        return tfidf

corpus = [
    "What is the weather like today",
    "what is for dinner tonight",
    "this is question worth pondering",
    "it is a beautiful day today"
]

tfidf = TfIdf()
tfidf_values = tfidf.add_corpus(corpus)
for tfidf_value in tfidf_values:
    print(tfidf_value)

1.2.2 用 sklearn 实现 TF-IDF 算法

  使用 sklearn 实现 TF-IDF 时,需要用到 TfidfVectorizer,具体代码如下:

from sklearn.feature_extraction.text import TfidfVectorizer


corpus = [
    "What is the weather like today",
    "what is for dinner tonight",
    "this is question worth pondering",
    "it is a beautiful day today"
]

tfidf_vec = TfidfVectorizer()

# 使用 fit_transform() 得到 TF-IDF 矩阵
tfidf_matrix = tfidf_vec.fit_transform(corpus)
print(tfidf_matrix)

# 使用 get_feature_names() 得到不重复的单词
print(tfidf_vec.get_feature_names())

# 得到每个单词对应的 ID
print(tfidf_vec.vocabulary_)

将输出如下信息:

  (0, 11)	0.3710221459250386
  (0, 6)	0.47059454669821993
  (0, 13)	0.47059454669821993
  (0, 9)	0.47059454669821993
  (0, 4)	0.24557575678403082
  (0, 14)	0.3710221459250386
  (1, 12)	0.506765426545092
  (1, 2)	0.506765426545092
  (1, 3)	0.506765426545092
  (1, 4)	0.2644512224141842
  (1, 14)	0.3995396830595886
  (2, 7)	0.4838025881780501
  (2, 15)	0.4838025881780501
  (2, 8)	0.4838025881780501
  (2, 10)	0.4838025881780501
  (2, 4)	0.25246826075544676
  (3, 1)	0.506765426545092
  (3, 0)	0.506765426545092
  (3, 5)	0.506765426545092
  (3, 11)	0.3995396830595886
  (3, 4)	0.2644512224141842
['beautiful', 'day', 'dinner', 'for', 'is', 'it', 'like', 'pondering', 'question', 'the', 'this', 'today', 'tonight', 'weather', 'what', 'worth']
{'what': 14, 'is': 4, 'the': 9, 'weather': 13, 'like': 6, 'today': 11, 'for': 3, 'dinner': 2, 'tonight': 12, 'this': 10, 'question': 8, 'worth': 15, 'pondering': 7, 'it': 5, 'beautiful': 0, 'day': 1}

1.3 总结

  TF-IDF 的优点是简单快速,而且容易理解。

  TF-IDF 的缺点是有时候用词频来衡量文章中的一个词的重要性不够全面,有时候重要的词出现的可能不够多,而且这种计算无法体现位置信息,无法体现词在上下文的重要性。

参考

[1] 机器学习:生动理解TF-IDF算法

[2] TF-IDF算法原理及其使用详解

[3] 基于TF-IDF算法抽取文章关键词

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐