首页 > 解决方案 > 将 lambda 函数应用于 2D 数组并接收回 1D 数组

问题描述

我正在尝试将一个简单的 lambda 函数应用于 2D 数组上的行,但我不能完全让它工作。

作为 MWE 的问题:

# Data
D = np.hstack((np.ones(5).reshape(-1,1),2*np.ones(5).reshape(-1,1)))

array([[1., 2.],
       [1., 2.],
       [1., 2.],
       [1., 2.],
       [1., 2.]])

# Function
f = lambda x: x[0] + x[1]

由于某些原因,我只能指定一个 lambda 参数(即本例中的 2D 数组的行),并且不能将数组拆分为相应的列,即写入lambda x1,x2: .... 也就是说,我必须索引输入参数的列,而不是将这些作为单独的参数传递。

现在,当我执行以下操作时:

f(D)

我希望收到回复:

array([[3],
       [3],
       [3],
       [3],
       [3]])

可悲的是,这不是正在发生的事情。相反,我得到:

array([2., 4.])

即该函数被单独应用于每一列,即使那样,也不应用于整个输入数组,看起来,只是一行。

帮助将不胜感激。

谢谢

标签: pythonarraysanonymous-function

解决方案


为此有一个numpy辅助函数np.apply_along_axis

>>> import numpy as np
>>> D = np.hstack((np.ones(5).reshape(-1,1),2*np.ones(5).reshape(-1,1)))
>>> np.apply_along_axis(lambda x: x[0] + x[1], 1, D)
array([3., 3., 3., 3., 3.])

尽管您可能必须重新塑造结果:

>>> np.apply_along_axis(lambda x: x[0] + x[1], 1, D)[...,None]
array([[3.],
       [3.],
       [3.],
       [3.],
       [3.]])

无论如何,这不会很有效,它会比使用numpy矢量化操作慢得多,所以你应该这样做:

>>> D[..., [0]] + D[..., [1]]
array([[3.],
       [3.],
       [3.],
       [3.],
       [3.]])

如果可能的话。虽然,我想知道这实际上是否更有效:

>>> (D[..., 0] + D[..., 1])[...,None]
array([[3.],
       [3.],
       [3.],
       [3.],
       [3.]])

编辑:

是的,后者肯定更快:

>>> arr = D.repeat(100_000, 0)
>>> from timeit import timeit
>>> timeit("arr[..., [0]] + arr[..., [1]]", setup="from __main__ import arr, np ", number=1000)
1.7564522250000323
>>> timeit("(arr[..., 0] + arr[..., 1])[..., None]", setup="from __main__ import arr, np ", number=1000)
0.5029663629999845

当然,其中任何一个都比apply_along_axis

>>> timeit("np.apply_along_axis(lambda x: x[0] + x[1], 1, arr)", setup="from __main__ import arr, np ", number=10)
8.547392725000009

请注意,与我重复 1000 次的纯 numpy 版本相比,上面重复了10 次,但它仍然花费了 10 倍的时间,这快了 3 个数量级(对于 numpy 与 python 来说非常典型)。哎呀,我认为直接进入 Python 可能会更快,所以使用列表推导:

>>> timeit("np.array([x[0] + x[1] for x in arr])", setup="from __main__ import arr, np ", number=10)
2.1825029110000287

同样,请注意,上述内容仅重复了 10 次。如果我只做10次原始计时,只是为了直接显示鲜明的对比:

>>> timeit("arr[..., [0]] + arr[..., [1]]", setup="from __main__ import arr, np ", number=10)
0.023796129999936966
>>> timeit("(arr[..., 0] + arr[..., 1])[..., None]", setup="from __main__ import arr, np ", number=10)
0.007688513000061903

(arr[..., 0] + arr[..., 1])[..., None]因此,如果您想以数百到一千倍的速度前进,请坚持下去。


推荐阅读