【问题标题】:4 for loop optimization4 for循环优化
【发布时间】:2019-10-09 06:55:52
【问题描述】:

我有以下极其丑陋的代码:

def cell_hist(gradients):
    h, w, d  = gradients.shape
    window_size = 8
    res_h = int(h / window_size)
    res_w = int(w / window_size)
    bins_number = 9
    bin_width = (180 / bins_number)
    bins = [bin_width * x for x in range(bins_number)]
    result = np.zeros((res_h, res_w, bins_number))

    for a in range(res_h):
        for b in range(res_w):
            fragment = gradients[a*window_size:(a+1)*window_size, b*window_size:(b+1)*window_size]
            hist = np.zeros(bins_number)

            for row in fragment:
                for pixel in row:
                    nbin = int((pixel[1] // bin_width) % 9)
                    hist[nbin] += ((pixel[1] - bins[nbin]) / bin_width) * pixel[0]
                    if nbin != bins_number - 1:
                        hist[nbin+1] += ((bins[nbin+1] - pixel[1]) / bin_width) * pixel[0]
                    else:
                        hist[0] += ((180 - pixel[1]) / bin_width) * pixel[0]
            result[a,b] = hist
    return result

我知道这很糟糕,但我想不出任何优化来摆脱 4 个 for 循环。是否有任何棘手的 numpy 索引可能在这里有所帮助?非常感谢您的帮助!

gradients 参数是一个如下所示的矩阵:(w,h,2)。所以基本上有两个通道的图像。

【问题讨论】:

  • 您还应该解释您要使用该代码做什么:[SO]: How to create a Minimal, Complete, and Verifiable example (mcve)
  • 我知道你不会喜欢这个答案,但老实说我不知道​​。我只有需要使用的代码,我知道它会产生很好的结果,而且我知道它非常慢。这是我几乎可以肯定是瓶颈的部分。所以我试图在不详细说明的情况下对其进行重构,只是检查我的输出是否相同。
  • 不是我(不)喜欢这个答案。您没有解释代码应该做什么。你知道它应该做什么/做什么吗?这个问题似乎不成立。也许更合适的地方是:codereview.stackexchange.com
  • @CristiFati 请注意,CR 要求 OP 来解释他们的代码的作用。 Code Review 确实是在性能和​​可读性增强方面寻求帮助的好地方,但审阅者通常不喜欢先猜测代码的用途。
  • @MathieuGuindon:感谢您的提示。就个人而言,我没有访问该站点,但我认为它比这里更好。 @:同时:-1:idownvotedbecau.se/nomcve。添加缺少的细节,我会收回它。

标签: python python-3.x numpy optimization


【解决方案1】:

有一些方法可以减少“内部标签”,使用 itertools 和嵌套元素的组合。

但在我看来,没有办法正确地做到这一点。

首先,让我们想想你能做些什么,将这个庞大的代码拆分成几个函数,它们会在必要时相互调用,然后命名任何函数/部分,使其不仅不那么难看,而且提高可读性:)

例如,我会将其拆分为以下内容:

def cell_hist(gradients):
    h, w, d  = gradients.shape
    window_size = 8
    res_h = int(h / window_size)
    res_w = int(w / window_size)
    bins_number = 9
    bin_width = (180 / bins_number)
    bins = [bin_width * x for x in range(bins_number)]
    result = np.zeros((res_h, res_w, bins_number))

    for a in range(res_h):
        for b in range(res_w):
            result[a,b] = func2(a, b)

    return result

def func2(a, b):
    fragment = gradients[a*window_size:(a+1)*window_size, b*window_size:(b+1)*window_size]
    hist = np.zeros(bins_number)

    for row in fragment:
        for pixel in row:
            nbin = int((pixel[1] // bin_width) % 9)
            hist[nbin] += ((pixel[1] - bins[nbin]) / bin_width) * pixel[0]
            if nbin != bins_number - 1:
                hist[nbin+1] += ((bins[nbin+1] - pixel[1]) / bin_width) * pixel[0]
            else:
                hist[0] += ((180 - pixel[1]) / bin_width) * pixel[0]
    return hist

但是有很多变量你必须用它来传递,然后是保持简单的最有效方法。将它放在某个类中,这为您提供了一种简单的方法来记住 self. 中的变量,并清楚地保持代码什么是必要的,什么不是:)

换行对于可读性也很有用,检查一下: https://doingmathwithpython.github.io/breaking-long-lines-in-python.html

【讨论】:

    猜你喜欢
    • 2011-08-30
    • 1970-01-01
    • 2015-04-15
    • 1970-01-01
    • 2020-11-07
    • 2018-12-23
    • 2016-02-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多