通过移位索引在2d数组中移位数据

时间:2015-03-13 14:02:08

标签: python arrays numpy

我需要移动一个2D数组字段,即我有一个" previous_data"我通过移位索引访问的数组来创建我的" new_data"阵列。

我可以在非pythonic(和慢)循环中执行此操作,但非常感谢找到pythonic(和更快)解决方案的一些帮助!

非常感谢任何帮助和提示!

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import mpl

def nonpythonic():
    #this works, but is slow (for large arrays)        
    new_data = np.zeros((ny,nx))
    for j in xrange(ny):
        for i in xrange(nx):
            #go through each item, check if it is within the bounds
            #and assign the data to the new_data array
            i_new = ix[j,i]
            j_new = iy[j,i]
            if ((i_new>=0) and (i_new<nx) and (j_new>=0) and (j_new<ny)):
                new_data[j,i]=previous_data[j_new,i_new] 

    ef, axar = plt.subplots(1,2)
    im = axar[0].pcolor(previous_data, vmin=0,vmax=2)
    ef.colorbar(im, ax=axar[0], shrink=0.9)
    im = axar[1].pcolor(new_data, vmin=0,vmax=2)
    ef.colorbar(im, ax=axar[1], shrink=0.9)

    plt.show()

def pythonic():
    #tried a few things here, but none are working
    #-tried assigning NaNs to indices (ix,iy) which are out of bounds, but NaN's don't work for indices
    #-tried masked arrays, but they also don't work as indices
    #-tried boolean arrays, but ended in shape mismatches
    #just as in the nonworking code below
    ind_y_good = np.where(iy>=0) and np.where(iy<ny)
    ind_x_good = np.where(ix>=0) and np.where(ix<nx)

    new_data = np.zeros((ny,nx))

    new_data[ind_y_good,ind_x_good] = previous_data[iy[ind_y_good],ix[ind_x_good]]

#some 2D array:
nx = 20
ny = 30    
#array indices:
iy, ix = np.indices((ny,nx))
#modify indices (shift):
iy = iy + 1
ix = ix - 4
#create some out of range indices (which might happen in my real scenario)
iy[0,2:7] = -9999
ix[0:3,-1] = 6666

#some previous data which is the basis for the new_data:
previous_data = np.ones((ny,nx))
previous_data[2:8,10:20] = 2
nonpythonic()
pythonic()

这是上面的工作(非语音)代码的结果: nonpythonic working example of shifted data

1 个答案:

答案 0 :(得分:2)

我实现了pythonic的一个版本,该版本使用一些屏蔽和索引来复制nonpythonic - 请参阅下文。顺便说一句,我认为“新”索引应该是与新数组相对应的索引,而不是旧数组,但我已将其保留为现有函数。

要意识到的主要问题是,在您尝试问题时,您的条件

ind_y_good = np.where(iy>=0) and np.where(iy<ny)
ind_x_good = np.where(ix>=0) and np.where(ix<nx)

必须合并,因为我们必须始终拥有成对的xy索引。即如果x索引无效,那么y也是如此。

最后,如果索引实际上都是按常数因子移动的,那么你可以通过使用NumPy的roll函数并获取与有效区域对应的索引切片来使这更简单。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import mpl


def nonpythonic(previous_data, ix, iy, nx, ny):
    #this works, but is slow (for large arrays)        
    new_data = np.zeros((ny,nx))
    for j in xrange(ny):
        for i in xrange(nx):
            #go through each item, check if it is within the bounds
            #and assign the data to the new_data array
            i_new = ix[j,i]
            j_new = iy[j,i]
            if ((i_new>=0) and (i_new<nx) and (j_new>=0) and (j_new<ny)):
                new_data[j,i]=previous_data[j_new,i_new] 

    return new_data

def pythonic(previous_data, ix, iy):

    ny, nx = previous_data.shape
    iy_old, ix_old = np.indices(previous_data.shape)

    # note you must apply the same condition to both
    # index arrays
    valid = (iy >= 0) & (iy < ny) & (ix >= 0) & (ix < nx)

    new_data = np.zeros((ny,nx))

    new_data[iy_old[valid], ix_old[valid]] = previous_data[iy[valid], ix[valid]]
    return new_data


def main():
    #some 2D array:
    nx = 20
    ny = 30    
    #array indices:
    iy, ix = np.indices((ny,nx))
    #modify indices (shift):
    iy = iy + 1
    ix = ix - 4
    #create some out of range indices (which might happen in my real scenario)
    iy[0,2:7] = -9999
    ix[0:3,-1] = 6666

    #some previous data which is the basis for the new_data:
    previous_data = np.ones((ny,nx))
    previous_data[2:8,10:20] = 2
    data_nonpythonic = nonpythonic(previous_data, ix, iy, nx, ny)
    data_pythonic = pythonic(previous_data, ix, iy)

    new_data = data_nonpythonic
    ef, axar = plt.subplots(1,2)
    im = axar[0].pcolor(previous_data, vmin=0,vmax=2)
    ef.colorbar(im, ax=axar[0], shrink=0.9)
    im = axar[1].pcolor(new_data, vmin=0,vmax=2)
    ef.colorbar(im, ax=axar[1], shrink=0.9)
    plt.show()
    print(np.allclose(data_nonpythonic, data_pythonic))

if __name__ == "__main__":
    main()