Python曲线拟合报错TypeError:仅单元素数组可转为Python标量
Python曲线拟合报错:TypeError: only size-1 arrays can be converted to Python scalars
我尝试使用Python进行曲线拟合,代码如下:
import numpy as np import matplotlib.pyplot as plt import pandas as pd from scipy.optimize import curve_fit import math
vector = np.vectorize(np.int_) x_data = np.array([-5.0, -4, -3, -2, -1, 0, 1, 2, 3, 4]) x1 = vector(x_data) y_data = np.array([77, 81, 171, 303, 409, 302, 139, 115, 88, 89]) y1 = vector(y_data)
def model_f(x, a, b, c, d): return a/(math.sqrt(2*math.pi*d**2)) * math.exp( -(x-c)**2/(2*d**2) ) + b popt, pcov = curve_fit(model_f, x1, y1, p0=[3,2,-16, 2])
运行后出现错误:
TypeError: only size-1 arrays can be converted to Python scalars
我认为是math.sqrt()和math.exp()导致的问题,原以为对数组进行向量化处理可以解决,但并未生效,请问遗漏了什么?
问题根源
你对x、y数组做的向量化只是把元素转成int类型,但**math模块下的函数只支持单个数值输入,无法处理numpy数组的批量运算**。curve_fit在调用model_f时会传入整个x数组,这时math.sqrt、math.exp遇到数组就会报错,和你之前的数组向量化操作无关。
解决方法
把模型函数里的math相关函数全部替换成numpy的对应函数——numpy的函数原生支持数组运算:
修改后的model_f函数:
def model_f(x, a, b, c, d): return a/(np.sqrt(2*np.pi*d**2)) * np.exp( -(x-c)**2/(2*d**2) ) + b
另外补充两个优化点:
- 你对x_data、y_data做的
vector(np.int_)转换完全没必要,numpy数组本身可以直接传入curve_fit,转int不影响拟合结果,甚至会丢失原数据的浮点精度(虽然这里x、y本身是整数,但没必要多此一举)。 - 初始参数
p0=[3,2,-16, 2]可能需要调整,从你的y数据来看,峰值在x=-1附近,c的初始值可以设为-1,a的初始值可以设为400左右,这样拟合更容易收敛。
修改后的完整代码示例:
import numpy as np import matplotlib.pyplot as plt from scipy.optimize import curve_fit x_data = np.array([-5.0, -4, -3, -2, -1, 0, 1, 2, 3, 4]) y_data = np.array([77, 81, 171, 303, 409, 302, 139, 115, 88, 89]) def model_f(x, a, b, c, d): return a/(np.sqrt(2*np.pi*d**2)) * np.exp( -(x-c)**2/(2*d**2) ) + b # 调整初始参数,提升拟合收敛性 popt, pcov = curve_fit(model_f, x_data, y_data, p0=[400, 80, -1, 2]) # 验证拟合结果 x_fit = np.linspace(-5, 4, 100) y_fit = model_f(x_fit, *popt) plt.scatter(x_data, y_data, label='原始数据') plt.plot(x_fit, y_fit, 'r-', label='拟合曲线') plt.legend() plt.show()
内容的提问来源于stack exchange,提问作者Struggling_Student
相关产品推荐
相关产品推荐

