使用iminuit进行高维多元拟合时出现ValueError的问题求助
使用iminuit进行高维拟合时的ValueError问题解决
问题描述
使用iminuit执行多元拟合,二维拟合正常,但维度超过二维时出现错误:ValueError: too many values to unpack (expected 2)。
可正常运行的二维拟合代码
from iminuit import Minuit from iminuit.cost import LeastSquares import numpy as np def model1(xy, a, b, c): x, y = xy return a + (x ** b) + (y ** c) np.random.seed(1) data_x = np.linspace(0, 1, 10) data_y = np.linspace(0, 1, 10) data_terr = 0.1 data_t1 = model1([data_x,data_y], 2, 3, 10) + data_terr * np.random.randn(len(data_x)) least_squares = LeastSquares([data_x,data_y], data_t1, data_terr, model1) m1 = Minuit(least_squares, a=1.0, b=1.0, c=1.0) m1.migrad()
出错的三维拟合代码
from iminuit import Minuit from iminuit.cost import LeastSquares import numpy as np def model2(xyz, a, b, c, d): x, y, z = xyz return a + (x ** b) + (y ** c) + (z ** d) np.random.seed(1) data_x = np.linspace(0, 1, 10) data_y = np.linspace(0, 1, 10) data_z = np.linspace(0, 1, 10) data_terr = 0.1 data_t2 = model2([data_x,data_y, data_z], 2, 3, 10, 20) + data_terr * np.random.randn(len(data_x)) least_squares = LeastSquares([data_x, data_y, data_z], data_t2, data_terr, model2) m2 = Minuit(least_squares, a=1.0, b=1.0, c=1.0, d=1.0) m2.migrad()
错误输出
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) Cell In[30], line 16 13 least_squares = LeastSquares([data_x, data_y, data_z], data_t2, data_terr, model2) 15 m2 = Minuit(least_squares, a=1.0, b=1.0, c=1.0, d=1.0) ---> 16 m2.migrad() File ~/anaconda3/envs/minuit_fitting/lib/python3.9/site-packages/iminuit/minuit.py:702, in Minuit.migrad(self, ncall, iterate) 700 if self._precision is not None: 701 migrad.precision = self._precision --> 702 fm = migrad(ncall, self._tolerance) 703 if fm.is_valid or fm.has_reached_call_limit: 704 break File ~/anaconda3/envs/minuit_fitting/lib/python3.9/site-packages/iminuit/cost.py:594, in Cost.__call__(self, *args) 579 def __call__(self, *args: float) -> float: 580 """ 581 Evaluate the cost function. 582 (...) 592 float 593 """ --> 594 r = self._call(args) 595 if self.verbose >= 1: 596 print(args, "->", r) File ~/anaconda3/envs/minuit_fitting/lib/python3.9/site-packages/iminuit/cost.py:1721, in LeastSquares._call(self, args) 1719 def _call(self, args: Sequence[float]) -> float: 1720 x = self._masked.T[0] if self._ndim == 1 else self._masked.T[: self._ndim] -> 1721 y, yerror = self._masked.T[self._ndim :] 1722 ym = self._model(x, *args) 1723 ym = _normalize_model_output(ym) ValueError: too many values to unpack (expected 2)
错误原因
LeastSquares构造函数对输入的自变量格式有明确要求:当处理多维自变量时,需要传入二维数组(形状为(n_samples, n_dims)),而非多个一维数组组成的列表。
二维代码能运行是巧合:当传入两个一维数组时,LeastSquares会将其识别为1个维度的自变量+观测值y,刚好能完成拆分;但当传入三个一维数组时,它会错误地将前三个数组都当作自变量维度,导致后续拆分y和yerror时,剩余的元素数量不符合预期,触发ValueError。
修正后的三维拟合代码
方案1:调整自变量为二维数组(推荐)
将多维自变量合并为形状为(n_samples, n_dims)的二维数组,并修改模型函数适配该格式:
from iminuit import Minuit from iminuit.cost import LeastSquares import numpy as np def model2(x, a, b, c, d): # x是形状为(10,3)的二维数组,每一行对应一个样本的x,y,z值 x_vals = x[:, 0] y_vals = x[:, 1] z_vals = x[:, 2] return a + (x_vals ** b) + (y_vals ** c) + (z_vals ** d) np.random.seed(1) data_x = np.linspace(0, 1, 10) data_y = np.linspace(0, 1, 10) data_z = np.linspace(0, 1, 10) # 合并为二维数组 data_xyz = np.column_stack([data_x, data_y, data_z]) data_terr = 0.1 # 生成模拟数据时,需传入二维数组的转置(匹配模型原输入格式) data_t2 = model2(data_xyz.T, 2, 3, 10, 20) + data_terr * np.random.randn(len(data_x)) least_squares = LeastSquares(data_xyz, data_t2, data_terr, model2) m2 = Minuit(least_squares, a=1.0, b=1.0, c=1.0, d=1.0) m2.migrad()
方案2:保持模型函数格式,调整自变量传入方式
如果想保留原模型函数的解包写法,可将自变量整理为(n_dims, n_samples)的数组,同时通过LeastSquares的ndim参数明确指定维度数:
from iminuit import Minuit from iminuit.cost import LeastSquares import numpy as np def model2(xyz, a, b, c, d): x, y, z = xyz return a + (x ** b) + (y ** c) + (z ** d) np.random.seed(1) data_x = np.linspace(0, 1, 10) data_y = np.linspace(0, 1, 10) data_z = np.linspace(0, 1, 10) # 整理为(n_dims, n_samples)的数组 data_xyz = np.array([data_x, data_y, data_z]) data_terr = 0.1 data_t2 = model2(data_xyz, 2, 3, 10, 20) + data_terr * np.random.randn(len(data_x)) # 明确指定ndim=3,让LeastSquares正确识别自变量维度 least_squares = LeastSquares(data_xyz, data_t2, data_terr, model2, ndim=3) m2 = Minuit(least_squares, a=1.0, b=1.0, c=1.0, d=1.0) m2.migrad()
内容的提问来源于stack exchange,提问作者PitisCat
相关产品推荐
相关产品推荐

