python - 将 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.])
即该函数被单独应用于每一列,即使那样,也不应用于整个输入数组,看起来,只是一行。
帮助将不胜感激。
谢谢
解决方案
为此有一个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]
因此,如果您想以数百到一千倍的速度前进,请坚持下去。
推荐阅读
- bash - 循环遍历由 '\r\n' 分隔的列表并在 bash 中连接项目
- java - 如何在java或groovy中编写相当于python的os.path.relpath()
- python - 使用墨卡托投影:我只想为土地/国家着色,所有土地(南极洲除外)加上所有海洋都被着色
- visual-studio - Visual C++ 预处理器宏是根据子系统选择定义的
- r - 表 % 来自不同子集的分类变量
- arrays - 按类过滤对象数组不起作用
- laravel - 如何在 Laravel 上使用 Guzzle 在 Header 中传递 Zoho-oauthtoken?
- matlab - 根据索引是偶数还是奇数,使用 for 循环填充矩阵
- c# - 将带前导零的字符串转换为数字
- python - 线程无限循环和同步问题