我正在尝试找出一种更有效的方法来分析具有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参数已经改变。
答案 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秒。