大数据集的TFIDF

48 投票
4 回答
34525 浏览
提问于 2025-04-18 16:07

我有一个包含大约800万篇新闻文章的资料库,我需要把它们转化成一种叫做TFIDF的表示方式,形式是稀疏矩阵。我之前用scikit-learn这个工具处理过较少量的数据,效果还不错,但我觉得对于这么大的数据集,它可能不太适用,因为它会先把输入的数据加载到内存中,这个过程非常耗费资源。

有没有人知道,针对大数据集,提取TFIDF向量的最佳方法是什么?

4 个回答

-2

文档的长度
共同的词汇数量
这些词汇是常见的还是不常见的
每个词汇出现的次数

7

我用sklearn和pandas解决了这个问题。

首先,使用pandas的迭代器遍历你的数据集,创建一个包含所有单词的集合。然后,把这个集合用在CountVectorizer的词汇表中。这样,CountVectorizer就会生成一个稀疏矩阵的列表,所有矩阵的形状都是一样的。接下来,只需使用vstack将它们组合在一起。最终得到的稀疏矩阵包含了和CountVectorizer对象相同的信息(只是单词的顺序不同),并且与所有你的数据进行了匹配。

如果考虑时间复杂度,这个方法可能不是最优的,但在内存使用上表现不错。我在一个超过20GB的数据集上使用了这个方法。

我写了一段python代码(不是完整的解决方案),展示了一些属性,建议你写一个生成器或者使用pandas的分块功能来遍历你的数据集。

from sklearn.feature_extraction.text import CountVectorizer
from scipy.sparse import vstack


# each string is a sample
text_test = [
    'good people beauty wrong',
    'wrong smile people wrong',
    'idea beauty good good',
]

# scikit-learn basic usage

vectorizer = CountVectorizer()

result1 = vectorizer.fit_transform(text_test)
print(vectorizer.inverse_transform(result1))
print(f"First approach:\n {result1}")

# Another solution is

vocabulary = set()

for text in text_test:
    for word in text.split():
        vocabulary.add(word)

vectorizer = CountVectorizer(vocabulary=vocabulary)

outputs = [] 
for text in text_test: # use a generator
    outputs.append(vectorizer.fit_transform([text]))


result2 = vstack(outputs)
print(vectorizer.inverse_transform(result2))

print(f"Second approach:\n {result2}")

最后,使用TfidfTransformer

15

我觉得你可以用一个叫 HashingVectorizer 的工具,把你的文本数据转换成一个比较小的 csr_matrix 矩阵,然后再用 TfidfTransformer 来处理它。存储一个有800万行和几万个列的稀疏矩阵其实没那么麻烦。还有一个选择就是根本不使用TF-IDF,可能你的系统在没有它的情况下也能运行得不错。

在实际操作中,你可能需要对你的数据集进行抽样,有时候系统只用10%的数据就能学得很好。这是一个经验性的问题,事先没办法确定哪种策略最适合你的任务。在我没有看到学习曲线明显上升之前,我不会担心要扩展到800万份文档。

下面是我今天早上做的一个例子。你可以看到,随着我添加更多文档,系统的表现确实在提高,但现在的阶段似乎增加文档对结果影响不大。考虑到训练的时间,我觉得用500个文件来训练不值得我花时间。

31

Gensim有一个很高效的tf-idf模型,而且它不需要一次性把所有数据都放在内存里。

你的数据集只需要是一个可迭代的对象,这样就不需要一次性把整个数据集都加载到内存中。

根据评论,make_wiki脚本在笔记本电脑上处理维基百科大约需要50分钟。

撰写回答