大数据集的TFIDF
我有一个包含大约800万篇新闻文章的资料库,我需要把它们转化成一种叫做TFIDF的表示方式,形式是稀疏矩阵。我之前用scikit-learn这个工具处理过较少量的数据,效果还不错,但我觉得对于这么大的数据集,它可能不太适用,因为它会先把输入的数据加载到内存中,这个过程非常耗费资源。
有没有人知道,针对大数据集,提取TFIDF向量的最佳方法是什么?
4 个回答
文档的长度
共同的词汇数量
这些词汇是常见的还是不常见的
每个词汇出现的次数
我用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。
我觉得你可以用一个叫 HashingVectorizer
的工具,把你的文本数据转换成一个比较小的 csr_matrix
矩阵,然后再用 TfidfTransformer
来处理它。存储一个有800万行和几万个列的稀疏矩阵其实没那么麻烦。还有一个选择就是根本不使用TF-IDF,可能你的系统在没有它的情况下也能运行得不错。
在实际操作中,你可能需要对你的数据集进行抽样,有时候系统只用10%的数据就能学得很好。这是一个经验性的问题,事先没办法确定哪种策略最适合你的任务。在我没有看到学习曲线明显上升之前,我不会担心要扩展到800万份文档。
下面是我今天早上做的一个例子。你可以看到,随着我添加更多文档,系统的表现确实在提高,但现在的阶段似乎增加文档对结果影响不大。考虑到训练的时间,我觉得用500个文件来训练不值得我花时间。
Gensim有一个很高效的tf-idf模型,而且它不需要一次性把所有数据都放在内存里。
你的数据集只需要是一个可迭代的对象,这样就不需要一次性把整个数据集都加载到内存中。
根据评论,make_wiki脚本在笔记本电脑上处理维基百科大约需要50分钟。