基于点集拟合倒数函数并指定终止零点的方法咨询
基于点集拟合倒数函数并指定终止零点的方法咨询
我完全理解你的困扰——多项式拟合确实不适合这种类似1/x的衰减趋势,尤其是你还需要曲线在指定x值处精确归零,普通多项式很难满足这个约束。下面是几个可行的思路,你可以试试:
1. 带约束的倒数形式函数拟合
既然你观察到曲线在峰值后是1/x式下降,我们可以构造一个带终止零点约束的倒数类函数,比如:f(x) = a * (1 - x / b) / x
这里的b就是你想要的终止x值(36、48或60),这样当x=b时,f(x)=0,完美满足你的终止条件。剩下的只需要拟合参数a,让函数尽可能贴近你已有的点集。
具体做法:
- 把已有的点(x_i, y_i)代入这个函数,转化为求解最小化误差的问题:
sum( (y_i - a*(1 - x_i/b)/x_i )^2 ) - 这是一个线性最小二乘问题,直接可以解出
a:a = (sum(y_i * x_i/(1 - x_i/b))) / sum( (x_i/(1 - x_i/b))^2 ) - 用numpy的话,你可以手动计算这个式子,或者用
scipy.optimize.curve_fit来拟合,把b固定为目标值,只拟合a。
2. 更灵活的衰减函数拟合(如果1/x不够精准)
如果简单的1/x变形不够贴合你的数据,可以试试带更多参数的衰减函数,同时保留终止零点约束,比如:f(x) = a * (1 - (x/b)^k) / x
这里k是额外的形状参数,用来调整衰减的快慢。你可以用scipy.optimize.curve_fit来拟合a和k,同时固定b为目标终止x值。这样既满足零点约束,又能更好地匹配数据的实际趋势。
3. 避免多项式拟合的坑
你之前用numpy.Polynomial.fit得到的结果不好,核心原因是多项式的趋势是无限增长/趋向某个值,而不是你需要的衰减到0的倒数趋势。而且多项式在插值点外的延伸通常会出现不符合预期的波动,完全不适合这种需要精准终止的场景,所以直接放弃多项式拟合就对了。
举个简单的代码示例(用scipy的curve_fit):
import numpy as np from scipy.optimize import curve_fit # 假设你的数据是x_data(到18)和y_data x_data = np.arange(1, 19) y_data = ... # 你的实际y值 # 定义带约束的函数,b是固定的终止x def fit_func(x, a): b = 36 # 这里换成你想要的48或60 return a * (1 - x / b) / x # 拟合参数a popt, _ = curve_fit(fit_func, x_data, y_data) a_fit = popt[0] # 生成拟合后的曲线数据 x_fit = np.arange(1, 61) y_fit = fit_func(x_fit, a_fit)
这个方法应该能解决你之前遇到的两个问题:一是拟合的曲线符合1/x式的衰减趋势,二是会精确在x=b处降到0,而且不会有多项式那种突兀的台阶。
备注:内容来源于stack exchange,提问作者RDGuida




