Python 中是否有类似于 R 中 apply 函数的相对应函数?

3

我想找到Python中类似于R的apply函数,但可以用于多维数组。

例如,当调用以下代码时:

z <- array(1, dim = 2:4)
apply(z, 1, sum)

结果如下:
[1] 12 12

当使用两个值作为margin参数调用时:

apply(z, c(1,2), sum)

结果为:
     [,1] [,2] [,3]
[1,]    4    4    4
[2,]    4    4    4

我发现numpy中的sum函数可以使用,但使用方法并不一致:
例如:
import numpy as np

xx= np.ones((2,3,4))
np.sum(xx,axis=(1,2))

结果如下:

array([12., 12.])

但是我找不到一个与apply函数相当的功能,特别是在处理margin=c(1,2)时。有人可以帮忙吗?

2个回答

6
NumPy 中的等价表达式为:
xx.sum(axis=2)

这意味着,您正在对轴2(即最后一维)进行求和,由于其长度为4,因此留下其他两个维度(2,3)作为结果的形状:

array([[4., 4., 4.],
       [4., 4., 4.]])

也许更直译你的R代码如下:
np.apply_over_axes(np.sum, xx, 2)

这会产生类似的结果,但是顺序被颠倒了。然而,这可能会更慢,并且如果你实际执行的操作比求和更复杂,那么这不是惯用语。


我一直在使用np.apply_along_axis,直到我发现了这个。 - AnhHao Trần

1

np.apply_over_axes与R的apply在几个方面不同。

首先,np.apply_over_axes需要指定要折叠的轴,而R的apply需要指定剩余的轴。

其次,np.apply_over_axes按迭代方式应用函数,如下所述文档。对于np.sum,结果是相同的,但对于其他函数可能不同。

func被调用为res = func(a,axis),其中axis是axes的第一个元素。函数调用的结果res必须与a具有相同的维度或比a少一维。如果res比a少一维,则在axis之前插入一个维度。然后在axes中的每个轴上重复使用func,以res作为第一个参数。

对于np.apply_over_axes,func需要采用特定格式,并且func的返回值需要采用特定形状才能正确执行np.apply_over_axes

这是一个关于编程的例子,展示了np.apply_over_axes失败的情况。
>>> arr.shape
(5, 4, 3, 2)
>>> np.apply_over_axes(np.mean, arr, (0,1))
array([[[[ 0.05856732, -0.14844212],
         [ 0.34214183,  0.24319846],
         [-0.04807454,  0.04752829]]]])
>>> np_mean = lambda x: np.mean(x)
>>> np.apply_over_axes(np_mean, arr, (0,1))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<__array_function__ internals>", line 5, in apply_over_axes
  File "/Users/kwhkim/opt/miniconda3/envs/rtopython2-pip/lib/python3.8/site-packages/numpy/lib/shape_base.py", line 495, in apply_over_axes
    res = func(*args)
TypeError: <lambda>() takes 1 positional argument but 2 were given

由于Python中似乎没有与之等价的函数,我编写了一个类似于R语言中的apply函数的函数。

def np_apply(arr, axes_remain, fun, *args, **kwargs):
    axes_remain = tuple(set(axes_remain))
    arr_shape = arr.shape
    axes_to_move = set(range(len(arr.shape)))
    for axis in axes_remain:
        axes_to_move.remove(axis)
    axes_to_move = tuple(axes_to_move)
    arr, axes_to_move
    arr2 = np.moveaxis(arr, axes_to_move, [-x for x in list(range(1,len(axes_to_move)+1))]).copy()
    #if arr2.flags.c_contiguous:
    arr2 = arr2.reshape([arr_shape[x] for x in axes_remain]+[-1])

    return np.apply_along_axis(fun, -1, arr2, *args, **kwargs)

至少对于上面的示例样本来说,它运行正常(结果可能与上面的结果不完全相同,但math.close()几乎对所有元素返回True)。

>>> np_apply(arr, (2,3), np.mean)
array([[ 0.05856732, -0.14844212],
       [ 0.34214183,  0.24319846],
       [-0.04807454,  0.04752829]])
>>> np_apply(arr, (2,3), np_mean)
array([[ 0.05856732, -0.14844212],
       [ 0.34214183,  0.24319846],
       [-0.04807454,  0.04752829]])

为了使该函数在大型多维数组中平稳运行,需要进行优化。例如,应防止数组复制。
总之,它似乎可以作为概念验证而发挥作用,希望能有所帮助。
PS) arrarr = np.random.normal(0,1,(5,4,3,2))生成。

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