python - 调用通过 Numpy 数组迭代的恒定时间函数会导致代码非常慢
问题描述
我有以下代码片段,它基本上执行以下操作:给定一个 2d numpy 数组arr
,计算sum_arr
如下:
sum_arr[i, j] = arr[i, j] + min(sum_arr[i - 1, j-1:j+2]) if (i>0) else arr[i, j]
j - 1 : j + 2
(当然,所有在0
和内的合理指数w
)
这是我的实现:
import numpy as np
h, w = 1000, 1000 # Shape of the 2d array
arr = np.arange(h * w).reshape((h, w))
sum_arr = arr.copy()
def min_parent(i, j):
min_index = j
if j > 0:
if sum_arr[i - 1, j - 1] < sum_arr[i - 1, min_index]:
min_index = j - 1
if j < w - 1:
if sum_arr[i - 1, j + 1] < sum_arr[i - 1, min_index]:
min_index = j + 1
return (i - 1, min_index)
for i, j in np.ndindex((h - 1, w)):
sum_arr[i + 1, j] += sum_arr[min_parent(i + 1, j)]
这就是问题所在:此代码片段仅执行 1e6 操作所需的时间太长(在我的机器上平均大约 5 秒)
有什么更好的方法来实现这一点?
解决方案
虽然您的操作是跨行顺序的,但在行内却不是。因此,很容易按行进行矢量化并只保留一个 1D 外循环,相对而言不应该产生太多开销。
事实上,这样做给了我约 200 倍的加速:
5.2975871179951355 # OP
0.023798351001460105 # vectorized rows
代码其实很简单:
import numpy as np
h, w = 1000, 1000 # Shape of the 2d array
arr = np.arange(h * w).reshape((h, w))
def min_parent(i, j, sum_arr):
min_index = j
if j > 0:
if sum_arr[i - 1, j - 1] < sum_arr[i - 1, min_index]:
min_index = j - 1
if j < w - 1:
if sum_arr[i - 1, j + 1] < sum_arr[i - 1, min_index]:
min_index = j + 1
return (i - 1, min_index)
def OP():
sum_arr = arr.copy()
for i, j in np.ndindex((h - 1, w)):
sum_arr[i + 1, j] += sum_arr[min_parent(i + 1, j, sum_arr)]
return sum_arr
def vect_rows():
h, w = arr.shape
if w==1:
return arr.cumsum(0)
out = np.empty_like(arr)
out[0] = arr[0]
for i in range(1, h):
out[i, :-1] = np.minimum(out[i-1, :-1], out[i-1, 1:])
out[i, 1:] = np.minimum(out[i, :-1], out[i-1, 1:])
out[i] += arr[i]
return out
assert np.allclose(OP(), vect_rows())
from timeit import repeat
print(min(repeat(OP, number=3)))
print(min(repeat(vect_rows, number=3)))
推荐阅读
- sql - SQL 表中的 XML - SQL Server
- haskell - 通过适当的获取和释放来流式传输资源
- gridview - Yii2 Gridview 列汇总基于计算的子值
- json - 如何在 spark 2.X 中验证 Json 模式?
- java - 在 Spring WebFlow 中获取 SnapshotNotFoundException
- android - 如何在 viewpager 下方添加另一个布局?
- amazon-ec2 - 如何在没有密钥对/pem 文件的情况下访问 AWS EC2 实例的 SSH
- c# - 通过 url 访问桌面应用程序
- javascript - 如何从函数内部的数据中正确返回值
- javascript - 浏览器“渲染引擎”和“javascript引擎”优化测试