如何使用numpy转换以下处理



我正在努力改进一部分代码,这部分代码大大降低了整个脚本的速度,甚至使其变得不可行。特别是这段代码是:

for vectors1 in EC1:
for vectors2 in EC2:
r = np.add(vectors1, vectors2)
for vectors3 in CDC:
result = np.add(r, vectors3).tolist()
if result not in states:  # This is what makes it very slow
states.append(result)

EC1、EC2和CDC是包含元素的列表,列表列表,作为一个迭代的例子,我们得到:

vectors1: [[2, 0, 0], [0, 0, 0], [0, 0, 0], [2, 0, 0], [0, 0, 0], [0, 0, 0], [2, 0, 0], [2, 0, 0], [0, 0, 0]]
vectors2: [[0, 0, 0], [2, 0, 0], [0, 0, 0], [0, 0, 0], [2, 0, 0], [2, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
vectors3: [[0, 0, 0], [0, 0, 0], [2, 1, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [2, 1, 0], [2, 1, 0]]
result:   [[2, 0, 0], [2, 0, 0], [2, 1, 0], [2, 0, 0], [2, 0, 0], [2, 0, 0], [2, 0, 0], [4, 1, 0], [2, 1, 0]]

请注意vectors1、vectors2和vectors3如何分别对应于EC1、EC2和CDC中的一个元素,以及"result"是vector1、vector2和vector3的总和,因此之前的向量不能以任何方式更改或排序,否则会更改"result(结果("变量的预期结果。

在前两个循环中,EC1和EC2中的每个项目都被求和,以便稍后将先前的结果与CDC中的项目相加。为了将EC1和EC2的列表以及上一个结果('r'(与CDC的列表相加,我使用numpy.add((。最后,我将'result'重新转换回列表。因此,基本上,我将列表列表作为EC1、EC2和CDC的元素进行管理。

问题是,我必须处理数十万(接近100万(的结果,并且必须检查状态列表中是否存在结果,这大大减缓了速度,特别是因为状态列表随着处理更多结果而增长。

我试图通过将所有内容作为numpy数组进行管理来保持对numpy世界的了解。首先声明状态为:

states = np.empty([9, 3], int)

然后,将结果numpy数组连接到状态numpy数组,然后检查状态中是否已经存在:

for vectors1 in EC1:
for vectors2 in EC2:
r = np.add(vectors1, vectors2)
for vectors3 in CDC:
result = np.add(r, vectors3)
if not np.isin(states, result).any():
np.concatenate(states, result, axis=0)

但我肯定做错了什么,因为结果并没有连接到状态,我也尝试过,但没有成功:

np.append(states, result, axis=0)

这能以某种方式并行化吗?

您可以使用广播在numpy中单独求和

res = ((EC1[:,None,:] + EC2).reshape(-1, 1, 3) + CDC).reshape(-1, 3)

假定EC1、EC2和CDC是阵列。

之后,您可以使用过滤出重复项

np.unique(res, axis=0)

但像Lucas一样,我强烈建议您提前过滤数组。对于您的示例数组,它将以res表示的行数从729缩减为8。

我不确定您正在处理的数据有多大,但这可能会在一定程度上加快速度:

EC1 = [[2, 0, 0], [0, 0, 0], [0, 0, 0], [2, 0, 0], [0, 0, 0], [0, 0, 0], [2, 0, 0], [2, 0, 0], [0, 0, 0]]
EC2 = [[0, 0, 0], [2, 0, 0], [0, 0, 0], [0, 0, 0], [2, 0, 0], [2, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
CDC = [[0, 0, 0], [0, 0, 0], [2, 1, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [2, 1, 0], [2, 1, 0]]
EC1.sort()
EC2.sort()
CDC.sort()
unique_triples = dict()
for v1 in EC1:
for v2 in EC2:
for v3 in CDC:
if str(v1)+str(v2)+str(v3) not in unique_triples: # list not hashable but strings are
unique_triples[str(v1)+str(v2)+str(v3)] = list(np.add(np.add(v1, v2), v3))

其基本思想是删除(EC1EC2CDC(条目的重复三元组,只对唯一的三元组进行加法运算,对列表进行排序,使其按字典顺序排列

字典有O(1(个查找,所以这些查找(可能(更快。

这是否更快可能取决于正在处理的数据的三元组的大小和唯一值的数量。

3矢量和是字典的值,例如。list(unique_triples.values())为我提供:

>>> list(unique_triples.values())
[[0, 0, 0], [2, 1, 0], [2, 0, 0], [4, 1, 0], [2, 0, 0], [4, 1, 0], [4, 0, 0], [6, 1, 0]]

我没有删除此处列表的原始列表中的重复项。如果您正在查看的应用程序允许,在迭代这些值之前,在EC1EC2CDC中删除这些重复项也可能是有益的。

最新更新