繁体   English   中英

如何在Python中并行化此查询(就像PLINQ一样)?

[英]How to parallelize this query in Python (just like PLINQ)?

我在Python中编写的查询遇到了一些问题(必须将其用于TensorFlow),它工作得很好,但是速度太慢了,因为输入数据集非常大。 查询可能需要5分钟以上的时间,然后检查任务管理器,我可以确认它确实在单个内核上运行。

这是代码:

# Assume words is a list of strings
for i, pair in enumerate(sorted(
    ((word, words.count(word))          # Map each word to itself and its count
        for word in set(words)),        # Set of unique words (remove duplicates)
    key=lambda p: p[1],                 # Order by the frequency of each word
    reverse=True)):                     # Descending order - less frequent words last

    # Do stuff with each sorted pair

我在这里所做的只是获取输入列表中的words ,消除重复项,然后根据输入文本中单词的出现频率以降序对单词进行排序。

如果要使用PLINQ在C#中编写此代码,则需要执行以下操作:

var query = words.AsParallel().Distinct()
            .OrderByDescending(w => words.Count(s => s.Equals(w)))
            .Select((w, i) => (w, i));

我找不到使用可能的内置库在Python中重写paralell实现的简单方法。 我看到了一些有关Pool扩展的指南,但看起来与并行Select操作等效,因此我仍然想念如何在Python中并行实现DistinctOrderByDescending操作。

可以使用内置库来做到这一点,还是有常用的第三方库来做到这一点?

谢谢!

当前方法的问题主要是基于for循环内的words.count(word) 这意味着您需要遍历set(words)每个唯一单词的整个列表,并且只对单个单词计数……相反,您可以使用Counter并单次通过列表。 Counter对象是一个字典,您可以使用O(1)进行频率查找来对键进行排序。 即使在我的例子1000“字样”,增速是显着的......更长的投入,我觉得无聊等待timeit完成:)

import string
from collections import Counter
import numpy as np # Just to create fake data

# Create some fake data
letters = list(string.ascii_lowercase)
new_words = [''.join(list(np.random.choice(letters, 3, replace=True))) 
             for x in range(1000)]


def original(search_list):
    """ Your current approach """
    for i, pair in enumerate(sorted(
    ((word, search_list.count(word)) 
        for word in set(search_list)),
    key=lambda p: p[1],
    reverse=True)):    
        pass


def new_approach(search_list):
    freq = Counter(search_list)
    search_list = sorted(search_list, key=lambda x: freq[x], reverse=True)
    new_list = []
    checked = set()
    for item in search_list:
        if item not in checked:
            new_list.append(item)
            checked.add(item)

有关1000个“单词”的列表:

%timeit original(new_words)
26.6 ms ± 289 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)


%timeit new_approach(new_words)
833 µs ± 30 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

在尝试使用诸如multiprocessing类的方法之前,您应该先查看这种新方法是否适合您的需求,因为这可能会增加额外的代码复杂性,而一旦解决了时间复杂性问题,则不必要。

编辑:

正如OP所指出的,我们可以跳过中间列表并通过简单地对Counter对象进行排序来进行设置:

def new_approach(search_list):
    freq = Counter(search_list)
    search_list = enumerate(sorted(freq, key=lambda x: freq[x], reverse=True))

新时机:

%timeit new_approach(new_words)
438 µs ± 6.31 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM