【问题标题】:Vectorizing a Nested Loop向量化嵌套循环
【发布时间】:2016-12-09 07:44:12
【问题描述】:

我希望对嵌套循环进行矢量化处理,该循环将适用于 300,000 个列表的列表,每个列表都包含 3 个值。嵌套循环将每个列表的值与其他列表中的对应值进行比较,并且只会附加对应值最大差异为 0.1 的列表索引。因此,包含 [0.234, 0.456, 0.567] 的列表和包含 [0.246, 0.479, 0.580] 的列表将属于此类别,因为它们的对应值(即 0.234 和 0.246;0.456 和 0.479;0.567 和 0.580)存在差异它们之间小于 0.1。

我目前使用以下嵌套循环来执行此操作,但目前大约需要 58 小时才能完成(总共 90 万亿次迭代);

import numpy as np
variable = np.random.random((300000,3)).tolist()
out1=list()
out2=list()
for i in range(0:300000):
    for j in range(0:300000):
        if ((i<j) and ((abs(variable[i][0]-variable[j][0]))<0.1) and ((abs(variable[i][1]-variable[j] [1]))<0.1) and ((abs(variable[i][2]-variable[j][2]))<0.1)):
        out1.append(i)  
        out2.append(j)

【问题讨论】:

  • 你的variable 是随机的,只是为了举例,还是你真的在模拟什么?
  • 是的,这只是为了举例 - 实际上我有一个列表列表,通过模拟生成,其中的数据实际上落在我提到的阈值范围内。

标签: python numpy vectorization


【解决方案1】:

查看 scipy.spatial;它有很多功能可以有效地解决此类空间查询;尤其是KDTrees,即:

import scipy.spatial
out = scipy.spatial.cKDTree(variable).query_pairs(r=0.1, p=np.infinity)

【讨论】:

  • 试过了;它返回“需要浮点数”。我假设这很简单;感谢您的回复!
  • 啊,我误解了文档;他们在这个问题上特别清楚。尝试编辑。 “无限范数”应该归结为您正在寻找的指标;任何组件的最大绝对值。
  • 请注意,为了提高效率,最好完全放弃列表,转而使用 ndarray。这适用于您的输入,也适用于输出;请注意,您可以将 output_type='ndarray' kwarg 添加到此调用中。
  • 在将 np.infinity 更改为 np.infty 后,它运行良好,但在 300,000 个列表上运行了几分钟后,它发出了“Killed”消息,结果证明这是一次内存问题再次。如何添加 output_type kwarg?
  • 查看我帖子中提供的链接以获取确切的签名。您收到内存错误的原因仍然是因为您生成的数据对的数量很大; np.random.random 生成的所有点都位于一个单位立方体中,因此 r=0.1 框内的邻居数量仍然很大。您确定这实际上代表了您的真实数据吗?
【解决方案2】:

转换为 NumPy 数组,以便之后更容易使用 NumPy 函数。然后,可以提出两种方法。

方法#1

NumPy 广播可用于将这些扩展到 3D 数组并以矢量化方式执行操作。因此,我们会有这样的实现 -

th = 0.1 # Threshold
arr = np.asarray(variable)
out1,out2 = np.where(np.triu((np.abs(arr[:,None,:] - arr) < th).all(-1),1))

方法 #2

专注于内存效率的替代实现,使用负责此类迭代的选择性索引 -

th = 0.1 # Threshold
arr = np.asarray(variable)
R,C = np.triu_indices(arr.shape[0],1)
mask = (np.abs(arr[R] - arr[C])<th).all(-1)
out1,out2 = R[mask], C[mask]

【讨论】:

  • 如果你有一个 TB 的内存就可以了,是的 :)
  • @EelcoHoogendoorn Approach #2 可能不那么重:)
  • 试过这个,但是内存溢出错误;仅用 30,000 个列表再次尝试并仍在运行;我猜它仍然需要相当长的时间?在 256Gb RAM 上运行
  • @JBorg 你试过Approach #2吗?另外,请尝试@Eelco Hoogendoorn 建议的基于KDTrees 的解决方案。
  • 仍然报告方法 #2 的 300,000 个列表的内存错误,并在大约 5-7 分钟内运行了 30,000 个列表。再次运行以检查实际时间。感谢您的回复,顺便说一句! :)
猜你喜欢
  • 2020-04-03
  • 1970-01-01
  • 1970-01-01
  • 2020-01-29
  • 2013-03-03
  • 2012-11-04
  • 2021-07-29
相关资源
最近更新 更多