HOWTO · NumPy
如何在 NumPy 中映射函数
使用 numpy.vectorize() 或 map() 和 lambda,将 Python 函数应用于 NumPy 数组中的每个值。了解每种方法的工作原理以及何时使用。
本页内容
要对 NumPy 数组中的每个值应用标量 Python 函数,可以用 numpy.vectorize() 包装该函数,也可以使用 Python 内置的 map() 配合 lambda,再将结果转换为数组。需要复用标量逻辑时,这两种方式都很有用;如果 NumPy 提供了等效的原生数组运算,通常优先使用该运算。
使用 numpy.vectorize() 逐元素应用函数
numpy.vectorize() 可以适配一次只接收一个值的函数,让你能够用数组调用它。它会逐个处理数组元素,并返回由处理结果组成的数组。如果现有 Python 逻辑是为标量编写的,而你想将它用于数组数据,这种方式会很方便。
下面的示例用一个计算输入平方的标量函数创建包装函数,然后将它应用于五个整数:
import numpy as np
def square(value):
return value ** 2
values = np.array([1, 2, 3, 4, 5])
square_each = np.vectorize(square)
result = square_each(values)
print(result)
这里的 square 仍是普通 Python 函数;np.vectorize() 提供了面向数组的调用接口。它只是一个便利包装器,并不会提升性能,也不会把该函数转换成编译后的 NumPy 运算。如果 NumPy 已支持相应的算术运算,直接写成 values ** 2 会更简单,也能直接使用 NumPy 的数组运算。当包装标量逻辑能让代码更清晰或更易复用时,可以使用 numpy.vectorize()。
使用 map() 和 lambda 函数
Python 内置的 map() 会对可迭代对象中的每一项调用一次函数。lambda 可以简洁地定义一个内联的小函数。输入为 NumPy 数组时,map() 会生成一个包含映射结果的迭代器;用 list() 包装该迭代器,再将得到的列表传给 np.array(),即可创建数组。
下面的示例使用 lambda 计算相同数值的平方,然后将映射结果转换为 NumPy 数组:
import numpy as np
values = np.array([1, 2, 3, 4, 5])
mapped_values = map(lambda value: value ** 2, values)
result = np.array(list(mapped_values))
print(result)
lambda 会分别接收数组中的每个值,而 map() 会依次生成每次返回的平方值。将迭代器转换为列表会消耗该迭代器;随后,np.array() 会根据这些值创建数组。对于适合紧挨着映射调用编写的简单标量运算,这种方式很方便。如果逻辑较长,可以定义一个具名函数,让代码更易阅读和维护,并用它代替 lambda 传给 map()。
如果想为现有标量函数提供面向数组的调用接口,可以选择 numpy.vectorize()。如果要进行简单的内联转换,可以选择 map() 和 lambda,尤其是在转换之前还需要使用生成的迭代器时。对于计算每个值的平方这类运算,如果 values ** 2 能准确表达所需计算,优先使用这个 NumPy 表达式。这些方法只是应用 Python 逻辑的不同方式,并不能说明其中一种映射方式比另一种更快。