R中几百个方程的高效嵌套优化

时间:2013-08-25 05:35:18

标签: r optimization iteration

我正在尝试找出一种更有效的方法来分析具有4个独立变量(x1,x2,x3和x4)和1个响应变量(y,可以是介于0和1之间的任何数字)的数据集。我正在尝试将我的数据拟合到一个带有6个参数的模型(3个斜率[m1,m2和m3]和3个截距[b1,b2和b3])。

通过求解下面的等式为零的y来计算每个点的y响应:

-x4+(x1/((log(-y/(y-1))-b1)/m1))
          +(x2/((log(-y/(y-1))-b2)/m2))
          +(x3/((log(-y/(y-1))-b3)/m3))

据我所知(如果有更好的方法,请纠正我),实现这一目标的最佳方法是用optimize()最小化上述等式的绝对值。以下是具有任意参数和x值的可重现示例:

#model parameters
b1=-8
b2=-10
b3=-15
m1=2
m2=25
m3=50

#independent variables
x1=3.9
x2=.02
x3=.01
x4=1

a=function(y) abs(-x4+(x1/((log(-y/(y-1))-b1)/m1))
      +(x2/((log(-y/(y-1))-b2)/m2))
      +(x3/((log(-y/(y-1))-b3)/m3)))

y=optimize(a,c(0,1))

使用这些输入,y的计算结果为~0.617。

足够简单,但我必须为500个数据点中的每一个执行此操作(每个数据点都有一个独特的x1,x2,x3,x4组合,但都具有相同的参数b1,b2,b3,m1,m2和M3)。我目前正在使用vapply(),但似乎必须采用更有效的方式。但是,我不知道如何对矢量化优化问题。

如果它在这里结束,那就不会那么糟糕了(所有500分在不到一秒的时间内用vapply()optimization()进行评估)。但这仅计算一组给定参数的y变量。当我尝试使用DEoptim()优化参数b1,b2,b3,m1,m2和m3以最大化对数似然时出现问题(然后我使用DEoptim()中的参数作为启动参数optim())中的参数微调。不用说,由于每个参数迭代都需要评估500个优化问题,这需要一段时间。奇怪的是,当我手动运行vapply来优化一组参数(即相当于DEoptim的单个迭代)时,它需要不到一秒钟,但每次迭代DEoptim()(也应该少于一个第二)大约需要10秒钟。我不知道为什么vapply()花了这么长时间(任何想法?),但我希望有一种方法可以更有效地解决所有500个方程。

在诉诸vapply()optimize()之前,我尝试了一些替代方法,包括使用Reduce()(而不是{{1})迭代计算y(同时在所有500个点) }),它有点快(每次迭代约6秒),但我认为我应该能够实现每次迭代<1秒(就像我手动运行optimize()的一个实例时)。如果我找不到更好的选择,我可能会回到vapply()

非常感谢任何帮助或见解。谢谢!

编辑为了澄清,指定的等式给出了指定参数和x值(由以下各项组成的500个数据点)的每个点的预测y值(其中等式为零) x1,x2,x3和x4的唯一组合,因此要计算500个唯一的y值; y是每个实例中唯一的未知值。总体目标是通过最大似然来优化参数,以获得最适合观察到的y值的预测y值。在每次参数优化迭代时,必须重新计算500 y值,因为m1 m2 m3和b1 b2 b3参数已经改变。

1 个答案:

答案 0 :(得分:3)

最好使用square作为目标函数而不是abs(),因为那时第一个导数是连续的。你可以通过

来看到这一点
curve(a,.001,.999)

并省略了abs并定义了这个函数

b=function(y) -x4+(x1/((log(-y/(y-1))-b1)/m1))+
              (x2/((log(-y/(y-1))-b2)/m2))+
              (x3/((log(-y/(y-1))-b3)/m3))

并绘制此函数的图表

curve(b,0.001,.9999)

一般来说,找到具有优化算法的方程组的解是不是一个好主意,因为它寻找任何最小值(全局和局部)。 您希望最小值为0.

因此最好使用非线性方程求解器。 有一个包nleqslv可以做到这一点(注意:我是该包的作者)。

由于您的函数已经过矢量化,因此无需使用Vectorize或其他矢量化方法。

定义一个函数f(与a相同而不是abs,效率稍高一些)

f <- function(y) {
    tmp <- log(-y/(y-1))
    -x4+(x1/((tmp-b1)/m1))+(x2/((tmp-b2)/m2))+(x3/((tmp-b3)/m3))

}

并定义一个计算雅可比的函数

fjac <- function(x) { h <- 0.00001*x; diag((f(x+h)-f(x))/h) }

可以非常有效地完成,因为f的返回值的每个元素仅取决于输入向量y的对应元素。

对于每个参数配置,y的数据向量和y的起始值可以通过

计算
z <- nleqslv(ystart,f,fjac, method="Newton")
y <- z$x

您必须使用方法Newton,因为方法Broyden在这种情况下不起作用。 你可以尝试这个例子

K <- 500
x1 <- x1 + c(0,runif(K-1,.1*x1,.3*x1))
x2 <- x2 + c(0,runif(K-1,.01*x2,.03*x2))
x3 <- x3 + c(0,runif(K-1,.01*x3,.03*x3))
x4 <- x4 + c(0,runif(K-1,.01*x4,.03*x4))
nleqslv(rep(.3,K),f,fjac, method="Newton")

在我的电脑上,大约需要0.08秒。