基础算法-> TF/IDF

707 阅读3分钟

tf-idf原理

  • en.wikipedia.org/wiki/Tf%E2%…

  • zh.wikipedia.org/wiki/Tf-idf

  • tf -- term frequency 是指词项出现在在一篇文档中的频率

  • idf -- inverse document frequency 在词频的基础上对每个词分配一个"重要性"的权重, 越常见的权重越低, 他的大小与词的常见程度成反比

  • tf-idf 是一种统计方法, 用来评估中一个词在一个文件集合中的重要程度

公式如下:

tf=某词在文章中出现的次数文章总词数tf = \frac {某词在文章中出现的次数} {文章总词数}

idf=log(文章总数1+包含该词的文档数) idf = \log(\frac {文章总数} {1 + 包含该词的文档数})

tfidf=tfidftf-idf = tf * idf

计算过程

以词语tit_i在文档djd_j为例,计算过程如下

tfi,j=ni,jknk,jtf_{i,j} = \frac {n_{i,j}} {\sum_k n_{k, j}}

nk,jn_{k, j} 表示词tkt_k在文档djd_j中出现的次数

idfi=log(D1+{j:tidj})idf_i = \log(\frac {|D|} {1 + |\{j: t_i \in d_j \}|})

其中D|D|表示文档总数,{j:tidj}|\{j: t_i \in d_j \}|表示包含词语tit_i的数目

代码


# 文章单词
documents_words_counter = [
    Counter(cut(str(content.iloc[i].content))) for i in range(mini_test_num)
]

def tf(word, i):
    words = cut(content.iloc[i].content)
    # word: count形式
    words_counts = Counter(words)
    return words_counts[word] / sum(words_counts.values())
    
def idf(word):
    """
    计算idf
    :param word 单词
    """
    return np.log(len(documents_words_counter) / (1 + sum(1 for counter in documents_words_counter if word in counter)))

def tfidf(word, i): 
    return tf(word, i) * idf(word)

例子:

  • 假如一篇文件的总词语数是100个,而词语“母牛”出现了3次,那么“母牛”一词在该文件中的词频(TF)就是3/100=0.03。
  • 而计算文件频率(IDF)的方法是以文件集的文件总数,除以出现“母牛”一词的文件数。所以,如果“母牛”一词在1,000份文件出现过,而文件总数是10,000,000份的话,其逆向文件频率就是lg(10,000,000 / 1,000)=4。
  • 最后的tf-idf的分数为0.03 * 4=0.12。

不足

tf-idf算法是创建在这样一个假设之上的:对区别文档最有意义的词语应该是那些在文档中出现频率高,而在整个文档集合的其他文档中出现频率少的词语,所以如果特征空间坐标系取tf词频作为测度,就可以体现同类文本的特点。另外考虑到单词区别不同类别的能力,tf-idf法认为一个单词出现的文本频数越小,它区别不同类别文本的能力就越大。因此引入了逆文本频度idf的概念,以tf和idf的乘积作为特征空间坐标系的取值测度,并用它完成对权值tf的调整,调整权值的目的在于突出重要单词,抑制次要单词。但是在本质上idf是一种试图抑制噪声的加权,并且单纯地认为文本频率小的单词就越重要,文本频率大的单词就越无用,显然这并不是完全正确的。idf的简单结构并不能有效地反映单词的重要程度和特征词的分布情况,使其无法很好地完成对权值调整的功能,所以tf-idf法的精度并不是很高。

此外,在tf-idf算法中并没有体现出单词的位置信息,对于Web文档而言,权重的计算方法应该体现出HTML的结构特征。特征词在不同的标记符中对文章内容的反映程度不同,其权重的计算方法也应不同。因此应该对于处于网页不同位置的特征词分别赋予不同的系数,然后乘以特征词的词频,以提高文本表示的效果