【问题标题】:TFIDF for Large Dataset大型数据集的 TFIDF
【发布时间】:2014-09-28 12:18:43
【问题描述】:

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

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

【问题讨论】:

  • 你见过thisthis吗?
  • @EdChum 此方法使用 HashingVectorizer (scikit-learn.org/stable/modules/generated/…) 来获取确实可扩展且最适合大型数据集的功能,但您可以在 cons 部分看到,它声明它不能用于计算 IDF 权重.
  • 如果不能全部放入内存或存储在 DB/pytables 中并执行查询以计算 tfidf 并存储为另一个表,则您必须迭代地执行此操作
  • 我需要一个 csr 矩阵,我认为迭代不会保留矩阵的形状,因为我们每次都会输入一批新数据并获得不同形状的矩阵,如果错了请纠正我.另外将如何考虑 idf 权重,它们是全局权重。使用 python 生成器是否会帮助您通过 CountVectorizer 计算 TF,然后将其转换为 IDF 权重?
  • 我相信您可以使用HashingVectorizer 从文本数据中获取较小的car_matrix,然后在其上使用TfidfTransformer。存储 8M 行和数万列的稀疏矩阵并不是什么大问题。

标签: python lucene nlp scikit-learn tf-idf


【解决方案1】:

文档的长度 共同术语的数量 术语是常见的还是不寻常的 每个术语出现的次数

【讨论】:

    【解决方案2】:

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

    使用 pandas iterator 在您的数据集中迭代一次并创建一组所有单词,然后在 CountVectorizer 词汇表中使用它。这样,Count Vectorizer 将生成一个稀疏矩阵列表,所有这些矩阵都具有相同的形状。现在只需使用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

    【讨论】:

      【解决方案3】:

      Gensim 有一个高效的tf-idf model 并且不需要一次将所有内容都保存在内存中。

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

      根据 cmets 的说法,make_wiki script 在笔记本电脑上以大约 50m 的距离在 Wikipedia 上运行。

      【讨论】:

      • 使用可迭代是实际可行的方法。我终于用 TfidfVectorizer 和一个可迭代的语料库
      • “可迭代”是什么意思?请你解释一下好吗?
      • @ivan_bilan 寻找python生成器,应该可以解释
      • gensim 需要一袋词才能在 tf-idf 上工作? radimrehurek.com/gensim/tut2.html#available-transformations
      • @apurva.nandan 你能解释一下如何使用 iterable 在 pandas 数据帧上执行 tfidf 吗?
      【解决方案4】:

      我相信您可以使用HashingVectorizer 从您的文本数据中获得较小的csr_matrix,然后在其上使用TfidfTransformer。存储 8M 行和数万列的稀疏矩阵并不是什么大问题。另一种选择是根本不使用 TF-IDF - 如果没有它,您的系统可能工作得相当好。

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

      下面是我今天早上正在做的一个例子。您可以看到,随着我添加更多文档,系统的性能趋于提高,但它已经处于似乎没什么区别的阶段。考虑到训练需要多长时间,我认为在 500 个文件上训练它不值得花时间。

      【讨论】:

      • 一旦我拥有它们,我基本上想计算所有文章的最近邻居(网页文本,所以大小非常大)。您是否建议我仍然应该忽略 IDF 计数并只计算令牌计数。顺便说一句,那么拆分数据并运行并行作业怎么样?但我想合并结果(矩阵及其不同的形状)会很麻烦。我正在可视化它们,所以之后也许我可以检查在哪里停止以及要获取多少数据。
      • PS 我提到持有稀疏的术语文档矩阵可能不是问题所在。乔纳森的回答说同样的话 - 保存所有网页的文本表示是困难的部分。但是,您可以通过流式传输(使用生成器)到矢量化器来解决这个问题。这就是gensim 实现如此小的内存占用的方式,即使在处理非常大的语料库时也是如此。看看这里的教程:radimrehurek.com/gensim/tut1.html
      • 是的,实际上我在 genism 主题出现之前就已经开始使用这种方法了,它使用惰性求值和 featurehasher 节省了大量内存。现在的问题是存储,我如何存储/转储这么大的 csr 矩阵,出现内存错误,有什么线索吗?
      • 如果您可以将其保存在内存中,则将其保存到磁盘应该没有问题。你用的是什么格式?是否正在向密集型转变?
      • 不,它只是一个 csr 矩阵,问题是我也使用了二元组和三元组,这导致大量内存使用。因此,泡菜无法倾倒如此大的矩阵。我开始通过 pytables 使用 HDF5 格式,现在一切都很好:)
      猜你喜欢
      • 2019-09-28
      • 1970-01-01
      • 2019-06-18
      • 2021-04-24
      • 2018-12-27
      • 2016-05-24
      • 2019-11-21
      • 2015-09-28
      • 2016-08-01
      相关资源
      最近更新 更多