人工智能NLP--特征提取之TF-IDF方法

349 阅读6分钟

一、前言

前面一篇文章讲了在NLP模型中将文本数据转换成数值数据的基础方法---词袋模型,那么现在笔者就带领大家来认识一下对词袋模型的另一种优化改进方法---TF-IDF

二、定义,组成和简介

TF-IDF(Term Frequency-Inverse Document Frequency)是一种在自然语言处理(NLP)中常用的权重计算方法,用于信息检索和文本挖掘。它是一种统计方法,用以评估一个词语对于一个文件集或一个语料库中的其中一份文件的重要程度。它的主要思想是:如果某个词语在一篇文章中出现的频率高(Term Frequency,TF),并且在其他文章中很少出现(Inverse Document Frequency,IDF),则认为这个词语具有很好的类别区分能力,对这篇文章的内容有很好的指示作用。

TF-IDF的组成部分:

  1. 词频(TF):
    • 词频表示某个词汇在文档中出现的次数。
    • 这个数字通常会被标准化(通常是词条频率除以文档中的词条总数),以防止它偏向长的文件。
    • 公式为:TF(t,d)=t在文档d中出现的次数文档d中的词条总数\text{TF}(t, d) = \frac{\text{t在文档d中出现的次数}}{\text{文档d中的词条总数}}
    • 代码演示:
TF(t, d) = count(t, d) / sum(count(w, d)), w∈d
  1. 逆文档频率(IDF):
    • 逆文档频率表示某个词汇在所有文档中出现的频率,表示词条的普遍重要性。
    • 当包含词条的文档越少,IDF越大,则说明词条具有很好的类别区分能力。
    • 公式为:IDF(t,D)=log文档总数包含词条t的文档数目\text{IDF}(t, D) = \log \frac{\text{文档总数}}{\text{包含词条t的文档数目}}
    • 为了防止分母为零,实际应用中通常会在分母上加1。
    • 代码演示:
IDF(t) = log(N / n(t))

完整的TF-IDF公式:

将TF和IDF相乘,就可以得到一个词条在一个文档中的重要性得分:

TF-IDF(t,d,D)=TF(t,d)×IDF(t,D)\text{TF-IDF}(t, d, D) = \text{TF}(t, d) \times \text{IDF}(t, D)

代码演示:

TF-IDF(t, d) = TF(t, d) * IDF(t)

TF-IDF的应用:

  1. 文本挖掘: 用于文本聚类、文档分类、信息检索等任务。
  2. 特征选择: 可以用来评估词条在文档中的重要性,以选择最重要的词条作为文档的代表。
  3. 数据标准化: 由于不同文档的长度可能不同,使用TF-IDF可以对文档进行标准化处理。

总之,通过计算TF-IDF,可以得到一个文档的特征向量,向量的每个维度对应一个词汇,其值表示该词汇在文档中的重要性。对于一个包含N个词汇的文档,其特征向量的长度为N。

三、TF-IDF的优缺点

TF-IDF的优点:

  • 能够反映出词条在文档中的重要性。
  • 能够减少常见词的影响,突出重要词条。

TF-IDF的缺点:

  • 对于词频非常高的词条,可能会造成权重过大的问题。
  • 没有考虑到词条的语义信息,例如“bank”既有“银行”的意思,也有“河岸”的意思,但TF-IDF无法区分。

改进方法:

  • TF-IDF的变种:如BM25,是一种在搜索引擎中常用的排名函数,它考虑了文档长度和词条频率。
  • 结合其他方法:如使用Word2Vec、BERT等词嵌入方法,将词条转换为向量,以捕捉词条的语义信息。

那么到这里,老粉都知道,上例子!!!!!

四、文本案例讲解演示TF-IDF

假设俺们有以下三个文档:

  1. "I love machine learning"
  2. "Machine learning is great"
  3. "Natural language processing is a part of artificial intelligence"

我们来计算每个词的TF-IDF值。

计算词频(TF)

首先,计算每个文档中的词频:

  • 文档1:{'I': 1, 'love': 1, 'machine': 1, 'learning': 1}
  • 文档2:{'Machine': 1, 'learning': 1, 'is': 1, 'great': 1}
  • 文档3:{'Natural': 1, 'language': 1, 'processing': 1, 'is': 1, 'a': 1, 'part': 1, 'of': 1, 'artificial': 1, 'intelligence': 1}

计算逆文档频率(IDF)

计算每个词的IDF值:

  • 'I': log(3/1)=1.0986log(3/1) = 1.0986
  • 'love': log(3/1)=1.0986log(3/1) = 1.0986
  • 'machine': log(3/2)=0.4055log(3/2) = 0.4055
  • 'learning': log(3/2)=0.4055log(3/2) = 0.4055
  • 'is': log(3/2)=0.4055log(3/2) = 0.4055
  • 'great': log(3/1)=1.0986log(3/1) = 1.0986
  • 'natural': log(3/1)=1.0986log(3/1) = 1.0986
  • 'language': log(3/1)=1.0986log(3/1) = 1.0986
  • 'processing': log(3/1)=1.0986log(3/1) = 1.0986
  • 'a': log(3/1)=1.0986log(3/1) = 1.0986
  • 'part': log(3/1)=1.0986log(3/1) = 1.0986
  • 'of': log(3/1)=1.0986log(3/1) = 1.0986
  • 'artificial': log(3/1)=1.0986log(3/1) = 1.0986
  • 'intelligence': log(3/1)=1.0986log(3/1) = 1.0986

计算TF-IDF值

计算每个文档中每个词的TF-IDF值:

  • 文档1:

    • 'I': 1×1.0986=1.09861 \times 1.0986 = 1.0986
    • 'love': 1×1.0986=1.09861 \times 1.0986 = 1.0986
    • 'machine': 1×0.4055=0.40551 \times 0.4055 = 0.4055
    • 'learning': 1×0.4055=0.40551 \times 0.4055 = 0.4055
  • 文档2:

    • 'machine': 1×0.4055=0.40551 \times 0.4055 = 0.4055
    • 'learning': 1×0.4055=0.40551 \times 0.4055 = 0.4055
    • 'is': 1×0.4055=0.40551 \times 0.4055 = 0.4055
    • 'great': 1×1.0986=1.09861 \times 1.0986 = 1.0986
  • 文档3:

    • 'natural': 1×1.0986=1.09861 \times 1.0986 = 1.0986
    • 'language': 1×1.0986=1.09861 \times 1.0986 = 1.0986
    • 'processing': 1×1.0986=1.09861 \times 1.0986 = 1.0986
    • 'is': 1×0.4055=0.40551 \times 0.4055 = 0.4055
    • 'a': 1×1.0986=1.09861 \times 1.0986 = 1.0986
    • 'part': 1×1.0986=1.09861 \times 1.0986 = 1.0986
    • 'of': 1×1.0986=1.09861 \times 1.0986 = 1.0986
    • 'artificial': 1×1.0986=1.09861 \times 1.0986 = 1.0986
    • 'intelligence': 1×1.0986=1.09861 \times 1.0986 = 1.0986

最后,将整个文本中的每一个词用具体计算出来的TF-IDF值代替即可。

看到这里,我相信有很多聪明的小伙伴一定注意到了一个问题,那就是文本中那些没有TF-IDF值的词(即TF-IDF值为零的词)怎么办 ? 以下笔者给出最常见的三种方法:

1. 忽略这些词

在大多数情况下,我们可以直接忽略这些词,因为它们对特定文档的特征贡献较小。例如,在文本分类或聚类任务中,我们只需要关注那些具有较高TF-IDF值的词。

2. 使用稀疏矩阵表示

在实际应用中,文档-词矩阵通常是稀疏的,即大部分元素为零。我们可以使用稀疏矩阵来存储和处理TF-IDF值,从而节省存储空间和计算资源。Python中的scipy.sparse模块提供了多种稀疏矩阵格式,可以方便地处理稀疏数据。

3. 处理未登录词(OOV)

对于在训练过程中未出现过的词(Out-Of-Vocabulary, OOV),可以采取以下策略:

  • 扩展词汇表:在训练过程中尽可能扩展词汇表,包含更多的词。
  • 使用预训练词向量:如Word2Vec、GloVe或BERT等预训练模型,这些模型通常包含大量的词汇,可以有效处理OOV问题。
  • 使用回退策略:如将OOV词映射到一个特殊的“未知词”标记。

五、TF-IDF示例代码

示例代码

下面是一个笔者使用TF-IDF并处理稀疏矩阵的示例代码:

from sklearn.feature_extraction.text import TfidfVectorizer
import numpy as np
import scipy.sparse

# 文档列表
documents = [
    "I love machine learning",
    "Machine learning is great",
    "Natural language processing is a part of artificial intelligence"
]

# 创建TF-IDF向量器
vectorizer = TfidfVectorizer()

# 计算TF-IDF矩阵
tfidf_matrix = vectorizer.fit_transform(documents)

# 将TF-IDF矩阵转换为稀疏矩阵格式
tfidf_sparse_matrix = scipy.sparse.csr_matrix(tfidf_matrix)

# 获取特征名称(词汇表)
feature_names = vectorizer.get_feature_names_out()

# 输出TF-IDF值
for doc_idx, doc in enumerate(tfidf_sparse_matrix):
    print(f"Document {doc_idx + 1}:")
    for word_idx in doc.indices:
        word = feature_names[word_idx]
        tfidf_value = doc[0, word_idx]
        print(f"  {word}: {tfidf_value:.4f}")

# 处理未登录词(OOV)的示例
new_documents = ["I enjoy deep learning and artificial intelligence"]
new_tfidf_matrix = vectorizer.transform(new_documents)

# 输出新文档的TF-IDF值
for doc_idx, doc in enumerate(new_tfidf_matrix):
    print(f"New Document {doc_idx + 1}:")
    for word_idx in doc.indices:
        word = feature_names[word_idx]
        tfidf_value = doc[0, word_idx]
        print(f"  {word}: {tfidf_value:.4f}")

详细的解释已在代码中给出

总结

TF-IDF是一种简单而有效的权重计算方法,在NLP领域有着广泛的应用。然而,随着深度学习技术的发展,越来越多的模型能够更好地捕捉词的语义信息,TF-IDF的使用可能会逐渐减少。

以上就是笔者关于TF-IDF技术的讲解,欢迎大家点赞,收藏,交流和关注,O(∩_∩)O谢谢!