如何向Python math模块函数传入向量?报错问题排查与解决
现有代码:
import numpy as np import math
给定函数列表 [lambda x: x ** 2, lambda x: x - 5, math.sin, math.cos],以及 x = np.linspace(-10, 10, 20),需要计算列表中每个函数在x上的y值。
尝试的代码:
def exe_function(x, funcs): y = [] for func in funcs: y.append(func(x)) return np.array(y)
预期返回一个行数为len(funcs)、列数为len(x)的numpy数组。
仅运行前两个函数时正常,但调用math.sin和math.cos时报错:
TypeError: only size-1 arrays can be converted to Python scalars
请问报错原因是什么?如何解决?(要求必须使用math模块的函数,不能替换)
报错原因
math模块的sin、cos函数仅支持单个标量数值作为输入,而你传入的x是长度为20的numpy数组,这类函数无法直接处理数组类型参数,因此抛出类型错误。
前两个lambda函数能正常运行,是因为numpy数组对**、-等运算符做了重载,支持向量化批量运算,可直接对整个数组执行计算。
解决方法
在不替换math模块函数的前提下,有两种常用方式处理numpy数组:
方法一:用np.vectorize包装math函数
np.vectorize可将仅支持标量的函数转换为支持数组输入的向量化函数,修改后的代码如下:
import numpy as np import math def exe_function(x, funcs): y = [] for func in funcs: if func in (math.sin, math.cos): vec_func = np.vectorize(func) y.append(vec_func(x)) else: y.append(func(x)) return np.array(y) # 测试 x = np.linspace(-10, 10, 20) funcs = [lambda x: x ** 2, lambda x: x - 5, math.sin, math.cos] result = exe_function(x, funcs) print(result.shape) # 输出 (4, 20),符合预期
方法二:手动遍历数组元素
通过循环逐个处理数组中的每个x值,再将结果组合为数组:
import numpy as np import math def exe_function(x, funcs): y = [] for func in funcs: if func in (math.sin, math.cos): res = [func(val) for val in x] y.append(np.array(res)) else: y.append(func(x)) return np.array(y) # 测试 x = np.linspace(-10, 10, 20) funcs = [lambda x: x ** 2, lambda x: x - 5, math.sin, math.cos] result = exe_function(x, funcs) print(result.shape) # 输出 (4, 20),符合预期
注意:np.vectorize本质是循环包装器,性能和手动遍历相近,适合小规模数据处理;若处理大规模数据,numpy原生的np.sin、np.cos效率更高,但本次要求必须使用math模块函数,以上两种方法均满足需求。
内容的提问来源于stack exchange,提问作者FliegendeButter

