【问题标题】:Randomly Indexing Multi-dimensional arrays in numpy在numpy中随机索引多维数组
【发布时间】:2019-11-19 04:31:24
【问题描述】:

如何更改此代码避免使用 python for-loop,而是使用 numpy 函数

h, w = 2, 2
im = np.random.randint(255, size=(h, w, 3))
index = np.random.randint(3, size=(h, w))
number = np.random.randint(255, size=(h, w))
for i in range(h):
    for j in range(w):
        im[i, j, index[i, j]] += number[i, j]

【问题讨论】:

  • 你正在做的是创建一个三层的 h * w 数组,用随机数填充它,然后为数组中的每个位置添加到随机层上的值。您到底想在这里替换什么?您是否想知道是否有一些特定于 numpy 的方法来更新整个数组的随机索引上的这些值?如果是这样,为什么?在这种情况下,for 循环有什么问题?

标签: python numpy multidimensional-array numpy-ndarray


【解决方案1】:

对于像您这样小的示例,您将很难加快循环代码的速度。 numpy 仅支付从某个问题大小向上产生的开销:

该图显示了原始循环代码 (OP) 与矢量化代码 (pp) 在像素总数 w x h 上的执行时间。

它是使用以下方法生成的:

from simple_benchmark import BenchmarkBuilder, MultiArgument
import numpy as np
from scipy.misc import face

B = BenchmarkBuilder()

@B.add_function()
def OP(im,index,number):
    im = im.copy()
    h,w,_ = im.shape
    for i in range(h):
        for j in range(w):
            im[i, j, index[i, j]] += number[i, j]
    return im

@B.add_function()
def pp(im,index,number):
    im = im.copy()
    h,w,_ = im.shape
    h,w = np.ogrid[:h,:w]
    im[h,w,index] += number
    return im

@B.add_arguments('#pixels')
def argument_provider():
    im = face()
    h,w,_ = im.shape
    mh,mw = h//2,w//2
    for exp in range(-8,1):
        fr = 2.**exp
        dh,dw = int(fr*mh),int(fr*mw)
        index = np.random.randint(3, size=(2*dh, 2*dw))
        number = np.random.randint(255, size=(2*dh, 2*dw),dtype=im.dtype)
        yield 4*dh*dw,MultiArgument([im[mh-dh:mh+dh,mw-dw:mw+dw],index,number])

r = B.run()
r.plot()

import pylab
pylab.savefig('randomchannel.png')

【讨论】:

    【解决方案2】:

    下面的代码与您的原始代码相同,但避免使用for 循环。但是,您为什么要这样做尚不清楚,因为我认为这个解决方案肯定比原来的解决方案更糟糕。

    from timeit import timeit
    import numpy as np
    
    h, w = 20, 20
    im = np.random.randint(255, size=(h, w, 3))
    
    
    def increase_random(x):
        result = np.copy(x)
        result[np.random.randint(3)] += np.random.randint(255)
        return result
    
    
    def loops():
        index = np.random.randint(3, size=(h, w))
        number = np.random.randint(255, size=(h, w))
        for i in range(h):
            for j in range(w):
                im[i, j, index[i, j]] += number[i, j]
    
    
    def vectorized():
        irv(im)
    
    
    irv = np.vectorize(increase_random, signature='(n)->(n)')
    
    print(timeit(vectorized, number=10))
    print(timeit(loops, number=10))
    

    我添加了一些时间测量来表明,在这种情况下,矢量化对提高性能没有任何帮助。在我的机器上,loops 代码大约快 25 倍。

    但是,如果您正在执行的操作更简单或更复杂但更易于优化,则它可能会从矢量化中受益。碰巧您的示例不太可能从中受益,而循环相当小且高效。

    【讨论】:

    • 与numpy相比,for循环不是很慢吗?
    • 并非如此,尽管它确实取决于您正在执行的操作类型。所以,当我说“不是真的”时,我的意思是“在这种特殊情况下不是”——但总的来说,矢量化往往是一个很大的改进。因此,如果您的示例只是一个示例,那么是的,矢量化应该更快。我将在答案中添加一些时间以进行比较。
    • 非常感谢,很好地解释了衡量它们之间的性能
    • np.vectorize 不是“真正的”numpy 向量化。它不会加快速度,尤其是签名版本。
    • 同意,这也是为什么函数的帮助文本指定“提供矢量化函数主要是为了方便,而不是为了性能。实现本质上是一个 for 循环。” - 但不如实际的 for 循环那么有效。
    猜你喜欢
    • 2015-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-05
    • 2020-03-25
    • 2018-01-22
    • 1970-01-01
    相关资源
    最近更新 更多