【问题标题】:Increasing the performance of a code snippet with nested for-loops使用嵌套的 for 循环提高代码片段的性能
【发布时间】:2020-10-20 21:44:25
【问题描述】:

我必须连续运行如下所示的 sn-p 大约 200000 次,并且 sn-p 需要大约 0.12585 秒来进行 1000 次迭代。数据点的形状为 (3, 2704, 64)

    output = []
    maxium = 0
    for datapoint in datapoints:
        tmp = []
        for data in datapoint:
            maxium = max(data)
            if maxium == 0:
                tmp.append(data)
            else:
                tmp.append(data / maxium)
        output.append(tmp)

我尝试使用 map() 重写它,但这给了我每次迭代平均 0.23237 秒的时间。这可能是由于多次调用 max(y) 和 list() 造成的。

np.asarray(list(map(lambda datapoint: list(map(lambda data: data / max(data) if max(data) > 0 else y, datapoint)), datapoints)))

是否有可能再次优化代码以提高性能?

【问题讨论】:

  • 对不起,我删除了我的评论,所以你的评论现在没有多大意义!在我提出之后,我注意到你使用了np.asarray。我添加了 numpy 标记,因为该解决方案肯定会涉及 numpy 的矢量化操作,而不是 Python for 循环或 map()
  • 我希望解决方案涉及numpy.amax() 函数。

标签: python performance numpy for-loop


【解决方案1】:

试试这样的:

maximum = datapoints.max(axis=2, keepdims=True)
output = np.where(maximum==0, datapoints, datapoints/maximum)

您会看到警告 invalid value encounter in true_divide,但它应该会按预期工作。


更新正如@ArthurTacca 指出的那样:

output = datapoints/np.where(maximum==0, 1, maximum)

将消除警告。

【讨论】:

  • 看来您不妨将第二行更改为datapoints / np.where(maximum==0, 1, maximum) 以避免错误。
【解决方案2】:

这里有一个简短的回答:

def bar(datapoints):
    m = np.amax(datapoints, axis=2)
    m[m == 0] = 1
    return datapoints / m[:,:,np.newaxis]

以下是您可能如何到达那里的解释(这就是我确实到达那里的方式!):

让我们从一些示例数据开始:

>>> x = np.array([[[1, 2, 3, 4], [11, -12, 13, -14]], [[26, 27, 28, 29], [0, 0, 0, 0]]])

现在检查你在原始函数上得到了什么:

def foo(datapoints):
    output = []
    maxium = 0
    for datapoint in datapoints:
        tmp = []
        for data in datapoint:
            maxium = max(data)
            if maxium == 0:
                tmp.append(data)
            else:
                tmp.append(data / maxium)
        output.append(tmp)
    return numpy.array(output)

结果是:

>>> foo(x)
array([[[ 0.25      ,  0.5       ,  0.75      ,  1.        ],
        [ 0.84615385, -0.92307692,  1.        , -1.07692308]],

       [[ 0.89655172,  0.93103448,  0.96551724,  1.        ],
        [ 0.        ,  0.        ,  0.        ,  0.        ]]])

现在让我们试试 amax:

>>> np.amax(x, axis=0)
array([[26, 27, 28, 29],
       [11,  0, 13,  0]])
>>> np.amax(x, axis=2)
array([[ 4, 13],
       [29,  0]])

啊哈,看起来axis=2 是我们所追求的。现在我们想除以原始数组,但仅限于最大值非零的地方。如何只在某些地方划分?答案是:我们处处除,但在某些地方我们除以 1,所以它没有效果。所以让我们用 1 替换 0:

>>> m = np.amax(x, axis=2)
>>> m[m == 0] = 1
>>> m
array([[ 4, 13],
       [29,  1]])

最后,让我们除以 broadcasting 回到我们之前取得最大值的轴 2:

>>> x / m[:,:,np.newaxis]
array([[[ 0.25      ,  0.5       ,  0.75      ,  1.        ],
        [ 0.84615385, -0.92307692,  1.        , -1.07692308]],

       [[ 0.89655172,  0.93103448,  0.96551724,  1.        ],
        [ 0.        ,  0.        ,  0.        ,  0.        ]]])

将所有这些放在一起,您会在顶部看到bar()

【讨论】:

    【解决方案3】:

    是的,您绝对可以通过矢量化 numpy 操作来加快速度。如果我理解您要正确执行的操作,我会这样做:

    import numpy as np
    
    # I use a randomly initialized array here, replace this with your input
    arr = np.random.random(size=(3, 2704, 64))
    
    # Find max for 3rd dimension, returns array w/ shape (3, 2704)
    max_arr = np.max(arr, axis=2) 
    
    # Set up divisor, returns array w/ shape (3, 2704)
    divisor = np.where(max_arr == 0, 1, max_arr)
    
    # Use expand_dims to add third dimension, returns array w/ shape (3, 2704, 1)
    divisor = np.expand_dims(divisor, axis=2)
    
    # Perform division, shape is (3, 2704, 64)
    ans = np.divide(arr, divisor)
    

    从您的代码中,我了解到您打算按第 3 轴的最大值缩放数据,但如果为 0,请放弃缩放。您似乎还希望您的输出与输入具有相同的形状,这解释了您构建outputtmp 的方式。这就是为什么我将代码 sn-p 以在 numpy 数组中结束 w/ 输出,但如果您需要它的原始形式,无论如何,它是一个简单的循环来重新排列您的数据:

    output = []
    for i in ans:
        tmp = []
        for j in i:
            tmp.append(list(j))
        output.append(tmp)
    

    为了将来参考,请提供更详细的问题。这将使人们更容易参与,并且您将增加快速回答问题的机会!

    【讨论】:

    • 我认为最后一部分你可以使用ans.tolist()
    猜你喜欢
    • 1970-01-01
    • 2012-11-25
    • 2021-12-01
    • 2019-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多