【问题标题】:Efficient way to find n most frequent words per category on text data在文本数据的每个类别中找到 n 个最常用词的有效方法
【发布时间】:2021-10-29 04:36:56
【问题描述】:

我正在尝试优化以下计算,因为没有子集很难在普通笔记本电脑上计算它(因为 RAM),这只是实际问题的示例。我需要指导如何加快速度。

我相信我需要使用稀疏矩阵,因为这是典型的问题,但我不确定如何在没有 pandas 的情况下处理它。或者,也许有一个帮助程序库经过优化可以执行此类操作。

如果不是,我正在考虑使用 dask 并行计算一些计算。

示例数据:

from sklearn.datasets import fetch_20newsgroups
import pandas as pd
import random

data = fetch_20newsgroups(subset='train')
data = pd.DataFrame({'text': data.data[:1000]})

CAT1 = [f'cat1_{i}' for i in range(3)]
CAT2 = [f'cat2_{i}' for i in range(10)]

data['cat1'] = [random.choice(CAT1) for _ in range(data.shape[0])]
data['cat2'] = [random.choice(CAT2) for _ in range(data.shape[0])]
data

我的计算:

from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer(ngram_range=(1, 3), min_df=5, max_df=1.0)
X = vectorizer.fit_transform(data['text'])
topwords = pd.DataFrame(X.toarray(), index=pd.MultiIndex.from_frame(data[['cat1', 'cat2']]))
topwords.columns = vectorizer.get_feature_names()
topwords = topwords.reset_index().melt(id_vars=['cat1', 'cat2'],
                                                 var_name='WORDS',
                                                 value_name='Value')
topwords = topwords.groupby(['cat1', 'cat2', 'WORDS'])['Value'].sum().reset_index()
topwords = topwords.groupby(['cat1', 'cat2']).apply(lambda x: x.nlargest(10, 'Value'))
topwords.reset_index(drop=True, inplace=True)

[编辑]:这是我能做到的最好的了。我解决了 RAM 的问题。但它仍然太慢,因为字典上的那个 group by。我想知道我怎样才能做得更好。

from collections import Counter
data['text_count'] = data['text'].apply(lambda row: Counter(row.split())) # Wall time: 1.22 s
data = data.groupby(['cat1', 'cat2'])['text_count'].sum().reset_index() # Wall time: 2min 5s
data['top_words'] = data['text_count'].apply(lambda row: row.most_common(3)) # Wall time: 203 ms
data = data.explode('top_words') # Wall time: 4 ms
data = pd.DataFrame(data['top_words'].tolist(), 
                    columns= ['WORDS', 'Value'],  
                    index=pd.MultiIndex.from_frame(data[['cat1', 'cat2']])).reset_index() # Wall time: 27.5 ms

【问题讨论】:

    标签: python-3.x nlp countvectorizer


    【解决方案1】:

    Pandas 无疑是处理数据科学中任何数据的幼稚方法。我个人致力于基于 FAISS / Elastic 搜索索引的问答嵌入。 FAISS(Facebook AI Similarity Search)的美妙之处在于,它首先将整个语料库数据向量化到一个 n 维空间(n = # of features)。一个人可以执行许多查询操作

    Faiss 是一个用于高效相似性搜索和密集向量聚类的库。它包含在任意大小的向量集中搜索的算法,直到那些可能不适合 RAM 的向量。它还包含用于评估和参数调整的支持代码。 Faiss 是用 C++ 编写的,带有 Python/numpy 的完整包装器。一些最有用的算法是在 GPU 上实现的。它由 Facebook AI Research 开发。

    Faiss 包含多种相似性搜索方法。它假设实例表示为向量并由整数标识,并且向量可以与 L2(欧几里德)距离或点积或任何其他类型的相似性度量进行比较。与查询向量相似的向量是那些与查询向量具有最低 L2 距离或最高点积的向量。它还支持余弦相似度,因为这是归一化向量上的点积。

    通常,查询速度更快,因为它基于哈希映射(python 中的字典)。因此,如果我们需要一个值,我们只需要记住它的键和遍历操作是一个常数时间操作 O(1),而不是使用 Pandas 的 O(n*n),我们必须遍历 n 行和 n 列。如果您正在处理大型文本数据库,请查看elastic search。弹性搜索仍然是信息抽取的SOTA,是搜索引擎背后的核心概念。

    希望对您的问题有所帮助。

    【讨论】:

      【解决方案2】:

      所以这是我使用很少资源的最快方法:

      from collections import Counter    
      data = data.groupby(['cat1', 'cat2'])['text'].sum().reset_index() # Wall time: 15.4 ms
      data['text_count'] = data['text'].apply(lambda row: Counter(row.split())) # Wall time: 53.3 ms
      data['top_words'] = data['text_count'].apply(lambda row: row.most_common(3)) # Wall time: 15.6 ms
      data = data.explode('top_words') # Wall time: 0 ns
      data = pd.DataFrame(data['top_words'].tolist(), 
                          columns= ['WORDS', 'Value'],  
                          index=pd.MultiIndex.from_frame(data[['cat1', 'cat2']])).reset_index() # Wall time: 0 ms
      

      但也许有人有更优雅的方法。

      【讨论】:

        猜你喜欢
        • 2013-12-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-09
        • 1970-01-01
        • 2019-07-27
        • 1970-01-01
        • 2018-03-12
        相关资源
        最近更新 更多