[英]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中并行实现Distinct
和OrderByDescending
操作。
可以使用内置库来做到这一点,还是有常用的第三方库来做到这一点?
谢谢!
当前方法的问题主要是基于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.