如何在numpy中避免使用for循环?

2024-05-28 19:49:15 发布

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

我已经写了下面的代码,它完全符合我的要求,但是速度太慢了。我确信有办法使它更快,但我似乎找不到该怎么做。代码的第一部分只是显示什么是什么形状。在

两张测量图像(VV1HH1
预计算值,VV模拟和HH模拟,都依赖于3个参数(为(101, 31, 11)值预计算)
索引2只是将VVHH图像放在同一个ndarray中,而不是生成两个3d数组

VV1 = numpy.ndarray((54, 43)).flatten()
HH1 = numpy.ndarray((54, 43)).flatten()
precomp = numpy.ndarray((101, 31, 11, 2))

我们让三个参数中的两个变化

^{pr2}$

我知道我应该做的一件事就是尽可能多地删除for循环,但是我不知道如何在处理更多维度时使numpy.min正常工作。在

第二件事(如果它可以矢量化就不那么重要了,但仍然很有趣)我注意到它主要占用CPU时间,而不是RAM,但是我已经搜索了很长时间,但是我找不到一种方法在matlab中编写类似“parfor”而不是“for”的东西,(是否可以制作一个@parallel装饰器,如果我只是把for循环放在一个单独的方法中?)在

编辑:在回答詹妮卡瑞拉:是的,这确实改善了很多

for (vv,hh) in zip(VV1,HH1):
    comp+= numpy.min((vv-precomp[...,0])**2+(hh-precomp[...,1])**2, axis=2)

当然要快得多,但是有没有可能删除外部for循环呢?有没有一种方法可以使for循环并行,使用@parallel或其他东西?在


Tags: 方法代码图像numpyfor参数parallelhh
3条回答

并行化循环的一种方法是使用map来构造它。在这种情况下,可以使用multiprocessing.Pool来使用并行映射。在

我要改变这个:

for (vv,hh) in zip(VV1,HH1):
    comp+= numpy.min((vv-precomp[...,0])**2+(hh-precomp[...,1])**2, axis=2)

像这样的事情:

^{pr2}$

注意,dstack假设每个comp.ndim都是2,因为它将添加第三个轴,并沿着它求和。这会使它慢一点,因为你必须构建列表,对其进行堆栈,然后求和,但这些都是并行或numpy操作。在

我还将zip改为numpy操作np.column_stack,因为对于长数组,zip要慢得多,假设它们已经是1d数组(在您的示例中)。在

我不能很容易地测试这个,所以如果有问题,请随时告诉我。在

在计算机科学中,有一个Big O notation的概念,用来近似计算做某件事需要多少功。为了使程序更快,尽可能少做。在

这就是为什么Janne的答案要快得多,你只需要做更少的计算。更进一步地说,我们可以应用memoization的概念,因为您是CPU的,而不是RAM的。如果需要比下面的例子更复杂的话,可以使用memory library。在

class AutoVivification(dict):
        """Implementation of perl's autovivification feature."""
        def __getitem__(self, item):
            try:
                return dict.__getitem__(self, item)
            except KeyError:
                value = self[item] = type(self)()
                return value

memo = AutoVivification()

def memoize(n, arr, end):
    if not memo[n][arr][end]:
        memo[n][arr][end] = (n-arr[...,end])**2        
    return memo[n][arr][end]


for (vv,hh) in zip(VV1,HH1):
    first = memoize(vv, precomp, 0)
    second = memoize(hh, precomp, 1)
    comp+= numpy.min(first+second, axis=2)

任何已经计算过的东西都会被保存到字典中的内存中,我们可以在以后查找它,而不是重新计算。你甚至可以把所做的数学分解成更小的步骤,如果需要的话,每个步骤都要记下来。在

自动活字典只是为了更容易地将结果保存在memoize中,因为我很懒。同样,你可以记住你所做的任何数学运算,所以如果numpy.min很慢,也要记住它。在

这可以替换内部循环j和{}

comp0 = numpy.min((vv-precomp[...,0])**2+(hh-precomp[...,1])**2, axis=2)

这可能是整个循环的替代品,尽管所有这些索引都让我的思维有点紧张。(这将创建一个大型中间数组)

^{pr2}$

相关问题 更多 >

    热门问题