scipy curve_fit与Python math模块兼容问题及解决方法咨询
问题原因与解决方案
为什么会触发报错?
scipy.optimize.curve_fit 在拟合过程中,会向你定义的目标函数传入numpy数组作为自变量 x。而Python标准库的math模块函数(比如math.sin、math.pow)都是为单个Python标量设计的,它们无法直接处理numpy数组类型的输入,这就导致了TypeError: only length-1 arrays can be converted to Python scalars错误。
你测试的f1能正常运行,是因为乘法、加法这类运算符已经被numpy数组重载过了,可以直接支持向量化运算;内置的pow同理,numpy数组实现了对应的魔法方法,所以能处理数组输入,但math.pow这类专属标量的函数不行。
解决方法:让math模块函数兼容curve_fit
这里有两种常用的可行方案:
方案1:替换为numpy的对应函数(推荐)
numpy提供了所有math模块函数的向量化版本,这些函数原生支持numpy数组输入,运行效率也最高。修改你的代码如下:
from scipy.optimize import curve_fit import numpy as np # 直接导入numpy,使用它的数学函数 x_axis = np.asarray([np.pi * i / 6 for i in range(-6, 7)]) y_axis = np.asarray([np.sin(i) for i in x_axis]) def f1(x, m, n): return m * x + n coeff1, mat = curve_fit(f1, x_axis, y_axis) print(coeff1) def f2(x, m, n): return m * np.sin(x) + n # 用np.sin代替math.sin coeff2, mat = curve_fit(f2, x_axis, y_axis) print(coeff2)
方案2:用numpy.vectorize包装math函数(适合必须用math函数的场景)
如果你因为某些原因必须使用math模块的函数,可以用np.vectorize把它包装成支持数组输入的函数。注意:vectorize本质是循环处理数组元素,效率不如原生numpy函数,仅适合简单场景。
修改示例:
from scipy.optimize import curve_fit from math import sin, pi import numpy as np x_axis = np.asarray([pi * i / 6 for i in range(-6, 7)]) y_axis = np.asarray([sin(i) for i in x_axis]) # 把math.sin包装成支持数组输入的函数 vec_sin = np.vectorize(sin) def f2(x, m, n): return m * vec_sin(x) + n # 使用包装后的函数 coeff2, mat = curve_fit(f2, x_axis, y_axis) print(coeff2)
内容的提问来源于stack exchange,提问作者Mr. T
相关产品推荐
相关产品推荐

