如何在gensim中过滤低tf-idf词汇?

9 投票
4 回答
10228 浏览
提问于 2025-04-18 12:52

我正在使用 gensim 来处理一些自然语言处理的任务。我通过 dictionary.doc2bow 创建了一个语料库,其中 dictionarycorpora.Dictionary 的一个对象。现在我想在运行 LDA 模型之前,过滤掉那些 tf-idf 值较低的词汇。我查看了这个语料库类的 文档,但找不到访问这些词汇的方法。有什么建议吗?谢谢。

4 个回答

1

假设你有一个文档 tfidf_doc,这个文档是通过 gensim 的 TfidfModel() 生成的,另外还有一个对应的词袋文档 bow_doc。现在你想过滤掉那些在这个文档中 tfidf 值低于 cut_percent% 的词,你可以调用 tfidf_filter(tfidf_doc, cut_percent),这样就会返回一个经过筛选的 tfidf_doc

def tfidf_filter(tfidf_doc, cut_percent):

    sorted_by_tfidf = sorted(tfidf_doc, key=lambda tup: tup[1])
    cut_value = sorted_by_tfidf[int(len(sorted_by_tfidf)*cut_percent)][1]

    #print('before cut:',len(tfidf_doc))

    #print('cut value:', cut_value)
    for i in range(len(tfidf_doc)-1, -1, -1):
        if tfidf_doc[i][1] < cut_value:
            tfidf_doc.pop(i)

    #print('after cut:',len(tfidf_doc))

    return tfidf_doc

接下来,你想根据刚才得到的 tfidf_doc 来过滤 bow_doc,只需调用 filter_bow_by_tfidf(bow_doc, tfidf_doc),它会返回一个经过筛选的 bow_doc

def filter_bow_by_tfidf(bow_doc, tfidf_doc):
    bow_idx = len(bow_doc)-1
    tfidf_idx = len(tfidf_doc)-1

    #print('before :', len(bow_doc))

    while True:
        if bow_idx < 0: break

        if tfidf_idx < 0:
            #print('pop2 :', bow_doc.pop(bow_idx))
            bow_doc.pop(bow_idx)
            bow_idx -= 1
        if bow_doc[bow_idx][0] > tfidf_doc[tfidf_idx][0]:
            #print('pop1 :', bow_doc.pop(bow_idx))
            bow_doc.pop(bow_idx)
            bow_idx -= 1
        if bow_doc[bow_idx][0] == tfidf_doc[tfidf_idx][0]:
            #print('keep :', bow_doc[bow_idx])
            bow_idx -= 1
            tfidf_idx -= 1

    #print('after :', len(bow_doc))

    return bow_doc
3

这段话的意思是,这个方法和之前的回答基本相同,但它额外处理了一些在tf-idf表示中得分为0的词。这些词是指在所有文档中都出现的词。之前的回答没有过滤掉这些词,所以它们仍然出现在最终的文本中。

#Same as before

dictionary = corpora.Dictionary(doc_list)
corpus = [dictionary.doc2bow(doc) for doc in doc_list]
tfidf = models.TfidfModel(corpus, id2word = dictionary)


#Filter low value words and also words missing in tfidf models.

low_value = 0.025

for i in range(0, len(corpus)):
    bow = corpus[i]
    low_value_words = [] #reinitialize to be safe. You can skip this.
    tfidf_ids = [id for id, value in tfidf[bow]]
    bow_ids = [id for id, value in bow]
    low_value_words = [id for id, value in tfidf[bow] if value < low_value]
    words_missing_in_tfidf = [id for id in bow_ids if id not in tfidf_ids] # The words with tf-idf socre 0 will be missing

    new_bow = [b for b in bow if b[0] not in low_value_words and b[0] not in words_missing_in_tfidf]  

#reassign        
corpus[i] = new_bow
3

这段内容虽然有点老了,但如果你想要按每个文档来查看,可以这样做:

#same as before
dictionary = corpora.Dictionary(doc_list)
corpus = [dictionary.doc2bow(doc) for doc in doc_list]
tfidf = models.TfidfModel(corpus, id2word = dictionary)

#filter low value words
low_value = 0.025

for i in range(0, len(corpus)):
    bow = corpus[i]
    low_value_words = [] #reinitialize to be safe. You can skip this.
    low_value_words = [id for id, value in tfidf[bow] if value < low_value]
    new_bow = [b for b in bow if b[0] not in low_value_words]

    #reassign        
    corpus[i] = new_bow
7

假设你的文本数据是这样的:

corpus = [dictionary.doc2bow(doc) for doc in documents]

在运行TFIDF之后,你可以得到一份低价值词汇的列表:

tfidf = TfidfModel(corpus, id2word=dictionary)

low_value = 0.2
low_value_words = []
for bow in corpus:
    low_value_words += [id for id, value in tfidf[bow] if value < low_value]

然后在进行LDA之前,把这些低价值的词汇从字典中去掉:

dictionary.filter_tokens(bad_ids=low_value_words)

现在重新计算一下文本数据,因为低价值的词汇已经被过滤掉了:

new_corpus = [dictionary.doc2bow(doc) for doc in documents]

撰写回答