Python,使用di的高效并行操作

2024-04-29 11:01:16 发布

您现在位置:Python中文网/ 问答频道 /正文

首先,对不起我的英语不太好。在

我想我的问题很容易解释。在

result={}
list_tuple=[(float,float,float),(float,float,float),(float,float,float)...]#200k tuples
threshold=[float,float,float...] #max 1k values
for tuple in list_tuple:
    for value in threeshold:
    if max(tuple)>value and min(tuple)<value:
        if value in result:
            result[value].append(tuple)
        else:
            result[value]=[]
            result[value].append(tuple) 

列表元组包含大约20万个元组,我必须非常快地执行此操作(在普通pc上最多2/3秒)。在

我的第一个尝试是在cython中使用prange()来实现这一点(这样我就可以从cython优化和并行执行中获得好处),但问题是(一如既往地),GIL:在prange()中,我可以使用cython memviews管理列表和元组,但我不能将结果插入dict

在cython中,我也尝试使用c++std的无序映射,但现在的问题是我不能用c++生成数组的向量(这就是我dict的值)。在

第二个问题类似:

^{pr2}$

这里我还有另一个问题,如果要使用prange(),我必须使用一个自定义哈希函数来使用数组作为c++无序映射的键

如你所见,我的代码片段很容易并行运行。在

我想尝试使用numba,但可能会因为GIL而相同,我更喜欢使用cython,因为我需要一个二进制代码(这个库可能是商业软件的一部分,所以只允许使用二进制库)。在

一般来说,我希望避免使用c/c++函数,我希望找到的是一种并行管理dicts/list的方法,它具有cython的性能,尽可能多地保留在Python域中;但是我愿意接受所有的建议。在

谢谢


Tags: in列表forifvalueresultfloatmax
3条回答

@a_客人代码:

def foo1(data, thresh):
    data = np.asarray(data)
    thresh = np.asarray(thresh)
    condition = (
       (data.min(axis=1)[:, None] < thresh)
       & (data.max(axis=1)[:, None] > thresh)
       )
    result = {v: data[c].tolist() for c, v in zip(condition.T, thresh)}
    return result

此代码为thresh中的每个项创建一个字典条目。在

操作代码,用default_dict(来自collections)稍微简化了一点:

^{pr2}$

对于符合条件的每个条目,此项更新一次词典条目。在

以及他的样本数据:

^{3}$

时间测试:

In [29]: timeit foo1(data,thresh)
66.1 µs ± 197 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
# In [30]: timeit foo3(data,thresh)
# 161 µs ± 242 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [31]: timeit foo3(data.tolist(),thresh.tolist())
30.8 µs ± 56.4 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

数组上的迭代比使用列表慢。tolist()的时间最短;np.asarray的时间更长。在

对于较大的数据样本,array版本更快:

In [42]: data = np.random.randint(0,50,(3000,3))
    ...: thresh = np.arange(50)
In [43]: 
In [43]: timeit foo1(data,thresh)
16 ms ± 391 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [44]: %%timeit x,y = data.tolist(), thresh.tolist() 
    ...: foo3(x,y)
    ...: 
83.6 ms ± 68.6 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

编辑

由于这种方法基本上是在数据样本和阈值之间执行外部积,因此它会显著增加所需的内存,这可能是不需要的。An improved approach can be found here.我仍然保留这个答案以备将来参考,因为它是在{a2}中引用的。在

我发现与OP代码相比,性能的提高是~ 20的一个因素。在


这是一个使用numpy的示例。数据和操作都是矢量化的。注意,结果dict包含空列表,而不是OP的示例,因此可能需要额外的清理步骤(如果合适)。在

import numpy as np

# Data setup
data = np.random.uniform(size=(200000, 3))
thresh = np.random.uniform(size=1000)

# Compute tuples for thresholds.
condition = (
    (data.min(axis=1)[:, None] < thresh)
    & (data.max(axis=1)[:, None] > thresh)
)
result = {v: data[c].tolist() for c, v in zip(condition.T, thresh)}

通过使用numpy的矢量化功能,可以实现一些性能改进:

  1. 当前为每个阈值重新计算min和{}值。相反,它们可以被预先计算,然后针对每个阈值重用。在
  2. 数据样本的循环(list_tuple)是在纯Python中执行的。此循环可以使用numpy进行矢量化。在

在下面的测试中,我使用了data.shape == (200000, 3); thresh.shape == (1000,),如操作中所示。我还省略了对resultdict的修改,因为这取决于数据,这可能会使内存迅速溢出。在

应用1。

v_min = [min(t) for t in data]
v_max = [max(t) for t in data]
for mi, ma in zip(v_min, v_max):
    for value in thresh:
        if ma > value and mi < value:
            pass

{a}比cda}的性能提高。在

应用1。&;2.

^{pr2}$

{10}比cda}的性能提高。这种方法的另一个好处是它不包含对列表的增量append,这可能会降低程序的速度,因为可能需要重新分配内存。相反,它在一次尝试中创建每个列表(每个阈值)。在

相关问题 更多 >