适用于大型数据集的TFIDF

apu*_*dan 32 python lucene nlp tf-idf scikit-learn

我有一个包含大约800万条新闻文章的语料库,我需要将它们的TFIDF表示为稀疏矩阵.我已经能够使用scikit-learn来获得相对较少数量的样本,但我相信它不能用于如此庞大的数据集,因为它首先将输入矩阵加载到内存中,这是一个昂贵的过程.

有谁知道,提取大型数据集的TFIDF向量的最佳方法是什么?

Jon*_*den 24

gensim有一个高效的tf-idf模型,不需要一次将所有内容都存储在内存中.

http://radimrehurek.com/gensim/intro.html

您的语料库只需要是一个可迭代的,因此它不需要一次将整个语料库放在内存中.

根据评论,make_wiki脚本(https://github.com/piskvorky/gensim/blob/develop/gensim/scripts/make_wikicorpus.py)在笔记本电脑上以大约50米的速度在维基百科上运行.

  • 使用iterable是实际的方法.我终于使用[TfidfVectorizer](http://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html)与语料库的迭代 (2认同)

mba*_*rov 12

我相信你可以使用a 从你的文本数据中HashingVectorizer获取一小csr_matrix部分然后使用TfidfTransformer它.存储8M行和数万列的稀疏矩阵并不是什么大问题.另一种选择是根本不使用TF-IDF - 如果没有它,你的系统可能会运行得相当好.

在实践中,您可能需要对数据集进行二次采样 - 有时系统只需从所有可用数据的10%中学习即可.这是一个经验问题,没有办法事先告诉什么策略最适合您的任务.在我确信我需要它们之前,我不会担心扩展到8M文档(即直到我看到学习曲线显示出明显的向上趋势).

以下是今天早上我正在做的事情.随着我添加更多文档,您可以看到系统的性能趋于提高,但它已经处于似乎没什么差别的阶段.鉴于培训需要多长时间,我不认为在500个文件上进行培训是值得的.

  • PS我提到持有稀疏的术语 - 文档矩阵可能不会成为问题.乔纳森的回答说同样的事情 - 持有所有网页的文本表示是困难的部分.但是,您可以通过流式传输(使用生成器)到矢量器中来解决这个问题.这就是`gensim`即使在处理非常大的语料库时也能实现如此微小的内存占用.看看这里的教程:http://radimrehurek.com/gensim/tut1.html (2认同)

Fel*_*ges 7

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

使用 pandas迭代器在数据集中迭代一次并创建一组所有单词,然后在 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}")
Run Code Online (Sandbox Code Playgroud)

最后,使用TfidfTransformer