简体   繁体   English

如何使用numpy和strides来提高循环的性能

[英]How to use numpy and strides to improve performance of loop

I'm new to numpy and just heard about strides, but I'm having trouble getting my head wrapped around how to use them. 我刚接触numpy并且刚刚听说过大步,但是我很难让我的脑袋围绕如何使用它们。 I have a small loop that is very slow and it seems like a good example that might work for strides. 我有一个非常慢的小循环,它似乎是一个很好的例子,可能适用于步幅。

def semivariogram( ds, band, lag ):
    width = ds.RasterXSize
    height = ds.RasterYSize
    data = band.ReadAsArray( 0, 0, width, height ).astype(np.float)
    #print 'w: {}, h: {}'.format(width, height)

    sumw = 0.0
    sumh = 0.0
    for i in range(width-lag):
        for j in range(height-lag):
            sumw += data[i+lag,j]-data[i,j]
            sumh += data[i,j+lag]-data[i,j]

    Nh2 = 2.0*(width-lag)*(height-lag)

    return [sumw/Nh2, sumh/Nh2, (sumw/Nh2+sumh/Nh2)/2.0]

The line: 这条线:

data = band.ReadAsArray( 0, 0, width, height ).astype(np.float)

is reading one band of an image into an array of floats. 正在读取一个图像的一个带成一个浮点数。 And ds is a handle to an image like: ds是图像的句柄,如:

ds = gdal.Open('test.tif')

Ok, let's do this step by step. 好的,让我们一步一步来做。

You have: 你有:

sumw = 0.0
sumh = 0.0
for i in range(width-lag):
    for j in range(height-lag):
        sumw += data[i+lag,j]-data[i,j]
        sumh += data[i,j+lag]-data[i,j]

Let's split this into two loops for clarity 为清楚起见,我们将其拆分为两个循环

sumw = 0.0
for i in range(width-lag):
    for j in range(height-lag):
        sumw += data[i+lag,j]-data[i,j]
sumh = 0.0
for j in range(height-lag):
    for i in range(width-lag):
        sumh += data[i,j+lag]-data[i,j]

We can write data[i,j+lag] as data[:-lag,lag:][i,j] , and data[i,j] is data[:-lag,:-lag][i,j] (for our range of i and j , and assuming lag != 0). 我们可以将data[i,j+lag]data[:-lag,lag:][i,j]data[i,j]data[:-lag,:-lag][i,j] (对于我们的ij范围,假设滞后!= 0)。 So our loops become: 所以我们的循环成为:

sumw = 0.0
for i in range(width-lag):
    for j in range(height-lag):
        sumw += data[lag:,:-lag][i,j]-data[:-lag,:-lag][i,j]
sumh = 0.0
for j in range(height-lag):
    for i in range(width-lag):
        sumh += data[:-lag,lag:][i,j]-data[:-lag,:-lag][i,j]

But now we note that all our loops are just iterating over a simple index, [i,j] , so we can flatten them entirely: 但是现在我们注意到我们所有的循环只是迭代一个简单的索引[i,j] ,所以我们可以完全展平它们:

sumw = (data[lag:,:-lag] - data[:-lag,:-lag]).sum()
sumh = (data[:-lag,lag:] - data[:-lag,:-lag]).sum()

This can be made even faster by spotting that the sum of the difference is the difference of the sums: 通过发现差异的总和是总和的差异,可以更快地做到这一点:

sumw = data[lag:,:-lag].sum() - data[:-lag,:-lag].sum()
sumh = data[:-lag,lag:].sum() - data[:-lag,:-lag].sum()

At this point, you can think about the overall task visually: 此时,您可以直观地考虑整体任务:

在此输入图像描述

You want sumw as the sum over the green outline minus the sum over the red outline, and sumh as the sum over the blue outline minus the sum over the red outline. 你想sumw和作为绿色轮廓的总和减去红色轮廓的总和,并将sumh作为蓝色轮廓的总和减去红色轮廓的总和。

Here, we can make one of two simplifications: 在这里,我们可以进行两种简化之一:

  1. We note that most of the elements in the first sum are being removed from the second sum. 我们注意到第一笔中的大部分元素都是从第二笔中删除的。 In fact, the only elements for which this is not the case are [:lag] and [-lag:] . 实际上,唯一不属于这种情况的元素是[:lag][-lag:] So this becomes: 所以这变成了:

     sumw = data[-lag:,:-lag].sum() - data[:lag,:-lag].sum() sumh = data[:-lag,-lag:].sum() - data[:-lag,:lag].sum() 

    Which will be faster provided that lag < len(data) / 2 . 如果lag < len(data) / 2 ,哪个会更快。 Here, we are setting sumw = green - (red + magenta) , and sumh = blue - (red + yellow) 在这里,我们设置sumw = green - (red + magenta)sumh = blue - (red + yellow)

  2. We note that the second sum is repeated, so have 我们注意到第二个总和是重复的,所以有

     sum_shared = data[:-lag,:-lag].sum() sumw = data[lag:,:-lag].sum() - sum_shared sumh = data[:-lag,lag:].sum() - sum_shared 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM