我是R的新手,非常感谢您的帮助。 我有一个带约束的优化问题。虽然有几种方法可以解决R中的优化问题,但我无法正确解决我需要应用的约束问题。
假设我有三个类别的以下数据:
A<-c(99.1, 96.5, 94.4, 92.7, 91.5, 91.3, 91.4, 90.1, 87.1, 82.6, 76.4)
B<-c(146.4, 140.2, 133.6, 126.5, 118.7, 109.4, 101.2, 101.8, 103.7, 102.5, 98.3)
C<-c(237.5, 213.9, 191, 168.9, 147.4, 124.9, 108.3, 95.7, 84.4, 73.5, 63)
t<-seq(1:11)
DT<-cbind.data.frame(t,A,B,C)
我想将指数函数 y(t)拟合到每个类别中的数据点(最小化平方误差),以便 y(t)_c&gt; y(t)_b&gt; y(t)_a&gt; 0用于选定的 t [1; 15]
答案 0 :(得分:0)
我不会尝试将约束纳入回归。 只需构建三个单独的回归:
fit_loga <- lm(y ~ log(A) + t, data=DT)
fit_logb <- lm(y ~ log(B) + t, data=DT)
fit_logc <- lm(y ~ log(C) + t, data=DT)
fit_a <- exp(A)
fit_b <- exp(B)
fit_c <- exp(C)
然后验证它们是否满足该范围内的所有约束(或至少在每个整数数据点处):(fit_c > fit_b) & (fit_b > fit_a)
。只有不是,那我们就担心了。比如在模型中输入其他一些术语,可能是exp(t)
,I(t^2)
,poly(t, <order>)
......
编辑:我不知道solnp
包。
答案 1 :(得分:0)
我认为使用solnp
获取的错误消息主要是指不充分的约束。此外,正如文档中所述,需要将所有参数放在一个向量中。在对代码进行适当调整后,我能够直接实现y(t)_c > y(t)_b > y(t)_a > 0
的约束,而无需更改问题。最方便的方法是使用求解器的矩阵形成。
使用上面的数据,我得到了以下信息:
Results shown here
library(data.table)
library(Rsolnp)
t<-as.vector(10:20)
DT<-cbind.data.frame(A,B,C)
tlogDT<-transpose(log(DT))
# min[log(y)'- Ax-b]
# Arr = [A1 A2 .. An b1 b2 .. bn]
gofn = function(arrin)
{
arr = cbind(arrin[1:3],arrin[4:6])
sum(
(as.matrix(arr[,1])%*%t + arr[,2] - tlogDT)^2
)
}
nocross=t #defines the times where the curves are not allowed to intersect
ineqfn2=function(arrin)
{
#constrains:
# 0<f_a(t)<f_b(t)<f_c(t), for some t,
arr = cbind(arrin[1:3],arrin[4:6])
nextarr=as.matrix(rbind(rep(0,2),arr[1:(length(arr[,1])-1),]))
ineqmat=as.matrix(arr[,1])%*%nocross+arr[,2]-nextarr[,1]%*%nocross-nextarr[,2]
as.vector(t(ineqmat))
}
#lines should be aligned with the first startvalue
eqfn = function(arrin)
{
arr = cbind(arrin[1:3],arrin[4:6])
arr[,1]*t[1]+arr[,2]-tlogDT[,1]
}
#start values:
An=c(1,1,1)
bn=tlogDT[,1]
vstart=c(An,bn)
r <- solnp(
vstart, gofn,
eqfun = eqfn, eqB= c(0,0,0),
ineqfun = ineqfn2,
ineqLB = rep(0,length(DT[1,])*length(nocross)),
ineqUB = rep(5000,length(DT[1,])*length(nocross))
)
r$pars[1]
line1 = exp(r$pars[4]+r$pars[1]*t)
line2 = exp(r$pars[5]+r$pars[2]*t)
line3 = exp(r$pars[6]+r$pars[3]*t)
plot(t, DT[,3],log = "y")
points(t, DT[,2],col="green")
points(t, DT[,1],col="blue")
lines(t, line1,lwd=2, col = "blue", xlab = "Time (s)", ylab = "Counts")
lines(t, line2,lwd=2, col = "green", xlab = "Time (s)", ylab = "Counts")
lines(t, line3,lwd=2, col = "black", xlab = "Time (s)", ylab = "Counts")