当前位置: 首页 > 面试题库 >

Python向量化嵌套循环

宗乐池
2023-03-14
问题内容

在寻找和理解pythonic方法以优化嵌套的for循环中的以下数组操作时,我将不胜感激:

def _func(a, b, radius):
    "Return 0 if a>b, otherwise return 1"
    if distance.euclidean(a, b) < radius:
        return 1
    else:
        return 0

def _make_mask(volume, roi, radius):
    mask = numpy.zeros(volume.shape)
    for x in range(volume.shape[0]):
        for y in range(volume.shape[1]):
            for z in range(volume.shape[2]):
                mask[x, y, z] = _func((x, y, z), roi, radius)
    return mask

其中volume.shape(182、218、200)和roi.shape(3)都是ndarray类型;并且radiusint


问题答案:

方法1

这是向量化方法-

m,n,r = volume.shape
x,y,z = np.mgrid[0:m,0:n,0:r]
X = x - roi[0]
Y = y - roi[1]
Z = z - roi[2]
mask = X**2 + Y**2 + Z**2 < radius**2

可能的改进:我们可以通过numexpr模块加快最后一步的速度-

import numexpr as ne

mask = ne.evaluate('X**2 + Y**2 + Z**2 < radius**2')

方法#2

我们还可以逐步构建与形状参数相对应的三个范围,并在运行中对三个元素进行减法运算,roi而无需像之前使用那样实际创建网格np.mgrid。通过broadcasting出于效率目的使用会受益。实现看起来像这样-

m,n,r = volume.shape
vals = ((np.arange(m)-roi[0])**2)[:,None,None] + \
       ((np.arange(n)-roi[1])**2)[:,None] + ((np.arange(r)-roi[2])**2)
mask = vals < radius**2

简化版:感谢@Bi Rico在这里提出改进建议,因为我们可以使用它np.ogrid以更简洁的方式执行这些操作,例如-

m,n,r = volume.shape    
x,y,z = np.ogrid[0:m,0:n,0:r]-roi
mask = (x**2+y**2+z**2) < radius**2

运行时测试

功能定义-

def vectorized_app1(volume, roi, radius):
    m,n,r = volume.shape
    x,y,z = np.mgrid[0:m,0:n,0:r]
    X = x - roi[0]
    Y = y - roi[1]
    Z = z - roi[2]
    return X**2 + Y**2 + Z**2 < radius**2

def vectorized_app1_improved(volume, roi, radius):
    m,n,r = volume.shape
    x,y,z = np.mgrid[0:m,0:n,0:r]
    X = x - roi[0]
    Y = y - roi[1]
    Z = z - roi[2]
    return ne.evaluate('X**2 + Y**2 + Z**2 < radius**2')

def vectorized_app2(volume, roi, radius):
    m,n,r = volume.shape
    vals = ((np.arange(m)-roi[0])**2)[:,None,None] + \
           ((np.arange(n)-roi[1])**2)[:,None] + ((np.arange(r)-roi[2])**2)
    return vals < radius**2

def vectorized_app2_simplified(volume, roi, radius):
    m,n,r = volume.shape    
    x,y,z = np.ogrid[0:m,0:n,0:r]-roi
    return (x**2+y**2+z**2) < radius**2

时间-

In [106]: # Setup input arrays  
     ...: volume = np.random.rand(90,110,100) # Half of original input sizes 
     ...: roi = np.random.rand(3)
     ...: radius = 3.4
     ...:

In [107]: %timeit _make_mask(volume, roi, radius)
1 loops, best of 3: 41.4 s per loop

In [108]: %timeit vectorized_app1(volume, roi, radius)
10 loops, best of 3: 62.3 ms per loop

In [109]: %timeit vectorized_app1_improved(volume, roi, radius)
10 loops, best of 3: 47 ms per loop

In [110]: %timeit vectorized_app2(volume, roi, radius)
100 loops, best of 3: 4.26 ms per loop

In [139]: %timeit vectorized_app2_simplified(volume, roi, radius)
100 loops, best of 3: 4.36 ms per loop

因此,一如既往地broadcasting显示出疯狂地 10,000x 加快原始代码速度的魔力,并且比 10x
使用即时广播的操作创建网格要好得多!



 类似资料:
  • Python 不仅支持 if 语句相互嵌套,while 和 for 循环结构也支持嵌套。所谓嵌套(Nest),就是一条语句里面还有另一条语句,例如 for 里面还有 for,while 里面还有 while,甚至 while 中有 for 或者 for 中有 while 也都是允许的。 当 2 个(甚至多个)循环结构相互嵌套时,位于外层的循环结构常简称为 外层循环或 外循环,位于内层的循环结构常简

  • 问题内容: 我经常发现自己正在这样做: 在Python中有更简洁的方法吗?我在想一些类似的东西 问题答案: 您可以使用itertools.product:

  • 问题内容: 因此,我正在研究UVA问题,并且我有4个嵌套循环来遍历多边形列表(每个多边形都包含一个点列表,其中每个点都包含一个整数x和y来表示其坐标,即,polygon [0]是一个点,其坐标为面[0] .x和面[0] .y)。 我试图减少程序中for循环的数量,以使其更高效并降低运行时间。我的代码如下: 我尝试通过使用itertools.product使其变得更加高效,如下所示: 无论如何,我的

  • 我是Java的新手,我想使用循环来产生阶梯效果,但在每一行中添加越来越多的空格。这是我的密码- 最终的目标是让它打印以下内容: 但我的照片是这样的: 对不起,我知道这是初学者的东西,但我不知道还能去哪里。感谢任何帮助。多谢了。

  • 这里是Uni learning Python编程入门课程的初学者。直到我明白了大部分,现在我很困惑。 有人能解释为什么这会产生它输出的模式吗? 外循环触发器和() 然后内部循环触发器和() 然后它不会打印(6),因为

  • 本文向大家介绍clojure 解构嵌套向量,包括了clojure 解构嵌套向量的使用技巧和注意事项,需要的朋友参考一下 示例 您可以解构嵌套向量: