将函数应用于三维数字阵列各二维切片的有效方法

时间:2023-02-07 21:24:21

I want to apply a function that takes a 2D array (and returns one of the same shape) to each 2D slice of a 3D array. What's an efficient way of doing this? numpy.fromiter returns a 1D array and numpy.fromfunction needs to be applied to each coordinate individually.

我想对3D数组的每个2D切片应用一个函数,该函数接受一个2D数组(并返回一个相同形状的数组)。有什么有效的方法呢?numpy.fromiter返回一个一维数组,并且numpy.fromfunction需要分别应用于每个坐标。

Currently I am doing

目前我正在做

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

This gives me what I want, but the list comprehension is very slow. Also, func is a 1D derivative with particular boundary conditions. numpy.gradient only seems to do N-D derivatives with N the dimension of the array, but maybe there is another routine that will do the whole thing for me?

这给了我想要的,但是列表理解速度很慢。同时,func是具有特定边界条件的一维导数。numpy。梯度似乎只对N维数组做N- d的导数,但也许有另一个例程可以帮我做整个事情?

Edit: The list comprehension works, but I'm looking for a faster way of doing it. bar3D can be large, up to (500,500,1000). All the numpy routines I've found for applying functions to arrays seem to assume either the function or the array are 1D.

编辑:列表理解有效,但我正在寻找一种更快的方法。bar3D可以很大,最多(500,500,1000)。我发现的将函数应用到数组的所有numpy例程似乎都假定函数或数组是1D。

2 个解决方案

#1


1  

I don't know of any generic way to apply functions to N-D slices of arrays. But there are two ways to get around it.

我不知道如何将函数应用到N-D数组片上。但是有两种方法可以解决这个问题。

If what you want to do is apply a 1D derivative on each row or column of each 2D-slice, this is equivalent to applying the derivative to each 1D slice, and you can use np.apply_along_axis:

如果你想做的是对每个2d切片的每一行或每一列进行一维微分,这就相当于对每一个一维切片进行微分,你可以使用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.]]])

This differentiates the rows of each 2D slice. To differantiate each column do np.apply_along_axis(np.gradient, 2, values)

这将区分每个2D切片的行。为了区分每一列,请使用np.apply_along_axis(np)。梯度2值)

If you want to do something that requires two dimensions, you can usually get it through broadcasting and axis parameters. If for instance you want V[i, j] = sqrt((V[i,j]-V[i, j-1])^2+V[i, j]-V[i-1, j])^2 for each slice V you can do:

如果你想做一些需要二维的事情,你通常可以通过广播和轴参数得到它。例如如果你想V(i,j)=√6((V - V(i,j)(i,j - 1))^ 2 + V - V(i,j)[张j])^ 2每一块V你能做什么:

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]]])

It's a bit cumbersome to get the dimensions right, but it will usually be the most efficient solution.

正确的尺寸是有点麻烦,但它通常是最有效的解决方案。

This examples uses zeros at the boundries, if you need something else, you need to set normdiff[:, :, 0] and normdiff[:, 0, :] to the correct boundry values.

这个例子在boundries使用了0,如果您需要其他东西,您需要将normdiff[:,:, 0]和normdiff[:, 0,:]设置为正确的boundry值。

#2


-2  

Say you have an array, a:

假设你有一个数组,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 ]]])

You can access 2D slices like so:

您可以访问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]

#1


1  

I don't know of any generic way to apply functions to N-D slices of arrays. But there are two ways to get around it.

我不知道如何将函数应用到N-D数组片上。但是有两种方法可以解决这个问题。

If what you want to do is apply a 1D derivative on each row or column of each 2D-slice, this is equivalent to applying the derivative to each 1D slice, and you can use np.apply_along_axis:

如果你想做的是对每个2d切片的每一行或每一列进行一维微分,这就相当于对每一个一维切片进行微分,你可以使用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.]]])

This differentiates the rows of each 2D slice. To differantiate each column do np.apply_along_axis(np.gradient, 2, values)

这将区分每个2D切片的行。为了区分每一列,请使用np.apply_along_axis(np)。梯度2值)

If you want to do something that requires two dimensions, you can usually get it through broadcasting and axis parameters. If for instance you want V[i, j] = sqrt((V[i,j]-V[i, j-1])^2+V[i, j]-V[i-1, j])^2 for each slice V you can do:

如果你想做一些需要二维的事情,你通常可以通过广播和轴参数得到它。例如如果你想V(i,j)=√6((V - V(i,j)(i,j - 1))^ 2 + V - V(i,j)[张j])^ 2每一块V你能做什么:

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]]])

It's a bit cumbersome to get the dimensions right, but it will usually be the most efficient solution.

正确的尺寸是有点麻烦,但它通常是最有效的解决方案。

This examples uses zeros at the boundries, if you need something else, you need to set normdiff[:, :, 0] and normdiff[:, 0, :] to the correct boundry values.

这个例子在boundries使用了0,如果您需要其他东西,您需要将normdiff[:,:, 0]和normdiff[:, 0,:]设置为正确的boundry值。

#2


-2  

Say you have an array, a:

假设你有一个数组,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 ]]])

You can access 2D slices like so:

您可以访问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]