将函数应用于3D numpy数组的每个2D切片的高效方法

20

我想应用一个函数到3D数组的每个2D切片(并返回形状相同的数组)。有没有高效的方法?numpy.fromiter返回1D数组,而numpy.fromfunction需要对每个坐标单独应用。

目前我的做法是:

foo = np.array([func(arg, bar2D) for bar2D in bar3D])

这样做可以得到我想要的结果,但列表推导式非常慢。另外,func是具有特定边界条件的一维导数。numpy.gradient似乎只能执行N-D数组(其中N为数组的维度)的导数,但也许有另一种程序可以为我完成整个过程?

编辑:列表推导式可以正常工作,但我正在寻找更快的方法。 bar3D 可以很大,高达 (500, 500, 1000)。我找到的所有用于将函数应用于数组的 numpy 程序似乎都假定函数或数组为1D。

2个回答

1
我不知道有什么通用的方法可以将函数应用于N-D数组的切片。但是有两种方法可以解决这个问题。
如果您想在每个2D切片的每行或每列上应用1D导数,则相当于将导数应用于每个1D切片,您可以使用np.apply_along_axis:
values = np.arange(4)*np.arange(3)[:, None]+np.arange(2)[:, None, None]*2
>>> array([[[0, 0, 0, 0],
            [0, 1, 2, 3],
            [0, 2, 4, 6]],

       [[2, 2, 2, 2],
        [2, 3, 4, 5],
        [2, 4, 6, 8]]])

np.apply_along_axis(np.gradient, 2, values)
>>> array([[[ 0.,  0.,  0.,  0.],
            [ 1.,  1.,  1.,  1.],
            [ 2.,  2.,  2.,  2.]],

           [[ 0.,  0.,  0.,  0.],
            [ 1.,  1.,  1.,  1.],
            [ 2.,  2.,  2.,  2.]]])

这将区分每个2D切片的行。要区分每一列,请使用np.apply_along_axis(np.gradient, 2, values)

如果您想要执行需要两个维度的操作,通常可以通过广播和轴参数来完成。例如,如果您想要对每个切片V执行V[i, j] = sqrt((V[i,j]-V[i, j-1])^2+V[i, j]-V[i-1, j])^2,则可以执行以下操作:

xdiffs = np.zeros_like(values) 
xdiffs[:, 1:, :]= np.diff(values, axis=1) 

ydiffs = np.zeros_like(values)
ydiffs[:, :, 1:] = np.diff(values, axis=2)

diffnorms = np.linalg.norm(xdiffs, ydiffs)

>>> array(
  [[[ 0.        ,  0.        ,  0.        ,  0.        ],
    [ 0.        ,  1.41421356,  2.23606798,  3.16227766],
    [ 0.        ,  2.23606798,  2.82842712,  3.60555128]],

   [[ 0.        ,  0.        ,  0.        ,  0.        ],
    [ 0.        ,  1.41421356,  2.23606798,  3.16227766],
    [ 0.        ,  2.23606798,  2.82842712,  3.60555128]]])

调整尺寸有点繁琐,但通常是最有效的解决方案。

这个示例在边界处使用零,如果需要其他内容,则需要将normdiff [:,:,0]normdiff [:,0,:]设置为正确的边界值。


-5
假设你有一个数组 a:
>>> a=np.random.random((4,3,2))

array([[[ 0.27252091,  0.78545835],
        [ 0.83604934,  0.48509821],
        [ 0.77828735,  0.26630055]],

       [[ 0.98623474,  0.29839813],
        [ 0.15893604,  0.61870988],
        [ 0.62281607,  0.27193647]],

       [[ 0.47976331,  0.2471835 ],
        [ 0.77323041,  0.30137068],
        [ 0.52906156,  0.53950597]],

       [[ 0.59207654,  0.86355457],
        [ 0.50250812,  0.75688653],
        [ 0.91046136,  0.5785383 ]]])

您可以这样访问2D切片:

>>> for x in range(a.shape[0]):
        print a[x,:,:]

>>> for x in range(a.shape[1]):
        print a[:,x,:]

>>> for x in range(a.shape[2]):
        print a[:,:,x]

抱歉,这不是我想要的。我知道如何取切片(for bar2D in bar3D可以给我每个2D切片)。我想做的是对每个2D切片应用一个函数,并从中创建一个新数组。 - Yossarian
你可以创建另一个与 a 形状相同的数组,比如 b,然后用 b[x,:,:]=yourfunc(a[x,:,:]) 替换 print a[x,:,:] - Lee
这相当于我目前正在做的事情。实际上,它甚至比列表推导式更慢。我正在寻求一种针对大型三维数组的高效方法。 - Yossarian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接