2

我在寻找可以让我进行三次回归的 JavaScript 代码时遇到了最糟糕的情况。会自己写,但我对多项式数学的理解是次优的。

所以,这就是我要找的。给定一个数组数组的输入,其中内部数组是 [x,y],该函数会给我一个带有四个参数的数组形式的输出 - [a,b,c,d],其中 a 、b、c 和 d 是方程 y = ax^3 + bx^2 + cx + d 的参数。

示例:输入是这样的数组 [[2,5],[5,10],[07,15],[12,20],[20,25],[32,30],[50,35] ]。

这本质上是一个表格的表示:

| x | 是 |
|-----------------|
| 02 | 05 |
| 05 | 10 |
| 07 | 15 |
| 12 | 20 |
| 20 | 25 |
| 32 | 30 |
| 50 | 35 |

现在,输出将是 [0.000575085,-0.058861065,2.183957502,1.127605507]。这些是三次函数的 a、b、c 和 d 参数。

(仅供参考,我使用 Excel 的 LINEST 函数并使用数组函数 {1,2,3} 在上述数字集上运行它得到的输出)。

怎么可能做到这一点?非常感谢您的任何指导。

最好的,汤姆

4

2 回答 2

4

这是使用numeric.js库的uncmin无约束最小化器作为最小二乘问题(此处为 jsbin )来解决该三次方的真实有效代码:

var data_x = [2,5,7,12,20,32,50];
var data_y = [5,10,15,20,25,30,35];

var cubic = function(params,x) {
  return params[0] * x*x*x +
    params[1] * x*x +
    params[2] * x +
    params[3];
};

var objective = function(params) {
  var total = 0.0;
  for(var i=0; i < data_x.length; ++i) {
    var resultThisDatum = cubic(params, data_x[i]);
    var delta = resultThisDatum - data_y[i];
    total += (delta*delta);
  }
  return total;
};

var initial = [1,1,1,1];
var minimiser = numeric.uncmin(objective,initial);

console.log("initial:");
for(var j=0; j<initial.length; ++j) {
  console.log(initial[j]);  
}

console.log("minimiser:");
for(var j=0; j<minimiser.solution.length; ++j) {
  console.log(minimiser.solution[j]);
}

我得到结果:

 0.0005750849851827991
-0.05886106462847641
 2.1839575020602164
 1.1276055079334206

解释一下:我们有一个函数“cubic”,它评估一组参数params和一个值的一般三次函数x。这个函数被包装来创建目标函数,它接受一组参数,并通过目标函数从我们的数据集中运行每个 x 值,并计算平方和。这个函数uncmin从 numeric.js 传递给一组初始值;uncmin做艰苦的工作并返回一个对象,其solution属性包含优化的参数集。

要在没有全局变量的情况下执行此操作(淘气!),您可以拥有一个目标函数工厂:

var makeObjective = function(targetFunc,xlist,ylist) {
  var objective = function(params) {
    var total = 0.0;
    for(var i=0; i < xlist.length; ++i) {
      var resultThisDatum = targetFunc(params, xlist[i]);
      var delta = resultThisDatum - ylist[i];
      total += (delta*delta);
    }
    return total;
  };
  return objective;
};

您可以使用它来制造目标函数:

var objective = makeObjective(cubic, data_x, data_y); // then carry on as before

知道如何实际执行此操作将对很多人有很大帮助,所以我很高兴这个问题出现了。

编辑:澄清cubic

var cubic = function(params,x) {
  return params[0] * x*x*x +
    params[1] * x*x +
    params[2] * x +
    params[3];
};

Cubic 被定义为一个函数,它接受一个参数数组params和一个值x。给定params,我们可以定义一个函数f(x)。对于三次方,f(x) = a x^3 + b x^2 + c x + d因此有 4 个参数 ( [0]to [3]),并且给定这 4 个参数值,我们有一个f(x)带有 1 个输入的函数x

代码的结构允许您cubic用相同结构的另一个函数替换;它可能linear有2个参数:

var linear = function(params, x) {
    return params[0]*x + params[1];
};

其余代码将查看 的长度,params以便了解需要修改多少参数。

请注意,这整段代码试图找到一组参数值,这些参数值产生一条最适合所有数据的曲线;如果您想找到适合某些数据的最后 4 个点的值,您只需将这些值传递到data_xand中data_y

于 2014-03-14T16:11:25.833 回答
3

我将其表述为最小二乘问题。设M是这样形成的n ×4 矩阵:

x_1^3  x_1^2  x_1  1
x_2^3  x_2^2  x_2  1
  ⋮       ⋮      ⋮
x_n^3  x_n^2  x_n  1

然后计算 4×4 矩阵A = M T ⋅<i>M 和 4×1 列向量b = M T ⋅<i>y 并求解线性方程组 = b。结果向量ξ将包含您的系数ad

上面的描述可以很容易地从数学上理解正在发生的事情。然而,对于实现,特别是对于非常大的n,上述方法可能是不可行的。在这些情况下,您可以直接构建Ab,而无需显式构建M。例如,A 1,2 = sum(x_i^3 * x_i^2 for all i)。因此,您可以遍历所有i并将相应的值添加到相应的矩阵和向量条目中。

于 2014-03-11T09:17:19.190 回答