NumPy的ndarray:逐行和逐列操作

12
如果我想对一个ndarray按行(或列)应用一个函数,我需要寻找哪种方法?是使用ufuncs(似乎不是),还是某种类型的数组广播(也不是我要找的)? 编辑 我正在寻找类似于R的apply函数的东西。例如,
apply(X,1,function(x) x*2)

可以通过匿名定义的函数将2乘以X的每一行,也可以是命名函数。(当然,这只是一个愚蠢的编造例子,实际上不需要使用apply)。没有通用的方法可以沿着NumPy数组的“轴”应用函数,?


2
谈论具体问题会更容易些。你想要做什么?一个通用的“逐行应用此函数”的解决方案实际上就是一个for循环(在行或列上迭代非常容易)。通常有更有效率的方法。 - Joe Kington
R的apply相当于numpy.vectorize。虽然如此,使用它几乎总是一个坏主意...我从来没有见过你必须使用vectorize而不能重写函数直接操作ND数组的情况。(它很可能比R的apply不够灵活。我只是玩过R,从未深入使用过。)在您的示例中,您只需编写result = X * 2即可。 - Joe Kington
有趣的是,实际上R也有一个向量化函数,但要沿着“轴”应用它,我必须将数组拆分为逐行向量的列表或类似的东西...但感谢您的一般讨论。我可能会坚持循环,因为它似乎更“通用”。(在R中,您还可以只需执行X*2,这就是我说它很傻的原因 :)。 - hatmatrix
啊!抱歉,我刚才假设 R 的 apply 有点不同。你可以让 numpy 的 vectorize 操作行(将数组视为结构化数组,然后每个元素是一个向量),但这比它值得的麻烦多了(而且通常不比在行上进行 for 循环更快)。 - Joe Kington
不,实际上apply_along_axis在Python中循环。请查看源代码:https://github.com/numpy/numpy/blob/master/numpy/lib/shape_base.py 无论如何,调用Python函数的开销很大,因此将循环移动到C中不会带来太大差异。(可能会稍微快一些。)即使您从C中调用Python函数,其开销也相当昂贵。 - Joe Kington
显示剩余6条评论
1个回答

16

首先,很多 numpy 函数都有一个 axis 参数。使用这种方法可能可以更好地实现你想要的结果。

然而,一种通用的“按行应用函数”的方法看起来像这样:

import numpy as np

def rowwise(func):
    def new_func(array2d, **kwargs):
        # Run the function once to determine the size of the output
        val = func(array2d[0], **kwargs)
        output_array = np.zeros((array2d.shape[0], val.size), dtype=val.dtype)
        output_array[0] = val
        for i,row in enumerate(array2d[1:], start=1):
            output_array[i] = func(row, **kwargs)
        return output_array
    return new_func

@rowwise
def test(data):
    return np.cumsum(data)

x = np.arange(20).reshape((4,5))
print test(x)

请记住,我们只需使用以下代码即可完成完全相同的操作:

np.cumsum(x, axis=1)

通常有一种更好的方法可以使用numpy来实现,而不是使用通用方法。

编辑:

我完全忘记了这一点,但上面的方法本质上等同于 numpy.apply_along_axis

因此,我们可以将其重写为:

import numpy as np

def test(row):
    return np.cumsum(row)

x = np.arange(20).reshape((4,5))
print np.apply_along_axis(test, 1, x)

哇,非常优雅!但是基本上对于一个由numpy未定义的带有轴参数的用户定义函数来说,做法就是迭代每一行,并将其分配给预先分配的数组... - hatmatrix
是的。有其他方法可以做同样的事情(你甚至可以通过各种技巧让numpy.vectorize做一些疯狂的事情),但它们最终都会类似于上面的示例。就像我说的,你通常可以将用户定义的函数转换为各种需要带有轴参数的numpy函数的组合。有时这是更好的方法,有时不是。迭代(如上面的示例)通常使用的内存比“numpy-ified”版本少得多,尽管它通常更慢。 - Joe Kington

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