复杂反函数预测值的置信区间
confidence interval around predicted value from complex inverse function
我试图在某些预测值周围获得 95% 的置信区间,但我无法实现。
基本上,我估计的增长曲线是这样的:
set.seed(123)
dat=data.frame(size=rnorm(50,10,3),age=rnorm(50,5,2))
S <- function(t,ts,C,K) ((C*K)/(2*pi))*sin(2*pi*(t-ts))
sommers <- function(t,Linf,K,t0,ts,C)
Linf*(1-exp(-K*(t-t0)-S(t,ts,C,K)+S(t0,ts,C,K)))
model <- nls(size~sommers(age,Linf,K,t0,ts,C),data=dat,
start=list(Linf=10,K=4.7,t0=2.2,C=0.9,ts=0.1))
我有独立的尺寸测量值,我想预测年龄。所以函数的反函数,不是很直接,我是这样计算的:
model.out=coef(model)
S.out <- function(t)
((model.out[[4]]*model.out[[2]])/(2*pi))*sin(2*pi*(t-model.out[[5]]))
sommers.out <- function(t)
model.out[[1]]*(1-exp(-model.out[[2]]*(t-model.out[[3]])-S.out(t)+S.out(model.out[[3]])))
inverse = function (f, lower = -100, upper = 100) {
function (y) uniroot((function (x) f(x) - y), lower = lower, upper = upper)[1]
}
sommers.inverse = inverse(sommers.out, 0, 25)
x= sommers.inverse(10) #this works with my complete dataset, but not with this fake one
虽然这工作正常,但我需要知道围绕此估计值 (x) 的置信区间 (95%)。对于线性模型,例如 "predict(... confidence=)"。我还可以 bootstrap 该函数以某种方式获取与参数关联的分位数(未找到方法),然后使用这些参数的极值来计算可预测的最大值和最小值。但这看起来并不是真正的好方法....
如有任何帮助,我们将不胜感激。
回答后编辑:
所以这有效(在 Ben Bolker 的书中有解释,请参阅答案):
vmat = mvrnorm(1000, mu = coef(mfit), Sigma = vcov(mfit))
dist = numeric(1000)
for (i in 1:1000) {dist[i] = sommers_inverse(9.938,vmat[i,])}
quantile(dist, c(0.025, 0.975))
根据我提供的相当糟糕的假数据,这当然很糟糕。但是在真实数据上(我在重新创建时遇到问题),这没问题!
除非我弄错了,否则您将不得不使用常规(参数)自举或称为 "population predictive intervals" 的方法(例如,参见 chapter 7 of Bolker 2008 的第 5 节),这假设您的参数的抽样分布是多元正态分布。但是,我认为你可能有更大的问题,除非我在调整它时以某种方式搞砸了你的模型......
生成数据(注意随机数据实际上可能不利于测试您的模型 - 见下文...)
set.seed(123)
dat <- data.frame(size=rnorm(50,10,3),age=rnorm(50,5,2))
S <- function(t,ts,C,K) ((C*K)/(2*pi))*sin(2*pi*(t-ts))
sommers <- function(t,Linf,K,t0,ts,C)
Linf*(1-exp(-K*(t-t0)-S(t,ts,C,K)+S(t0,ts,C,K)))
绘制数据和初始曲线估计值:
plot(size~age,data=dat,ylim=c(0,16))
agevec <- seq(0,10,length=1001)
lines(agevec,sommers(agevec,Linf=10,K=4.7,t0=2.2,ts=0.1,C=0.9))
我在使用 nls
时遇到了麻烦,所以我使用了 minpack.lm::nls.lm
,它稍微稳健一些。 (这里还有其他选项,例如计算导数和提供梯度函数,或使用 AD Model Builder 或 Template Model Builder,或使用 nls2
包。)
对于nls.lm
我们需要一个函数returns残差:
sommers_fn <- function(par,dat) {
with(c(as.list(par),dat),size-sommers(age,Linf,K,t0,ts,C))
}
library(minpack.lm)
mfit <- nls.lm(fn=sommers_fn,
par=list(Linf=10,K=4.7,t0=2.2,C=0.9,ts=0.1),
dat=dat)
coef(mfit)
## Linf K t0 C ts
## 10.6540185 0.3466328 2.1675244 136.7164179 0.3627371
这是我们的问题:
plot(size~age,data=dat,ylim=c(0,16))
lines(agevec,sommers(agevec,Linf=10,K=4.7,t0=2.2,ts=0.1,C=0.9))
with(as.list(coef(mfit)), {
lines(agevec,sommers(agevec,Linf,K,t0,ts,C),col=2)
abline(v=t0,lty=2)
abline(h=c(0,Linf),lty=2)
})
这种拟合,反函数的结果会极度不稳定,因为反函数是多对一的,反函数的个数值敏感地取决于参数值...
sommers_pred <- function(x,pars) {
with(as.list(pars),sommers(x,Linf,K,t0,ts,C))
}
sommers_pred(6,coef(mfit)) ## s(6)=9.93
sommers_inverse <- function (y, pars, lower = -100, upper = 100) {
uniroot(function(x) sommers_pred(x,pars) -y, c(lower, upper))$root
}
sommers_inverse(9.938, coef(mfit)) ## 0.28
如果我选择间隔非常,我可以得到正确答案...
sommers_inverse(9.938, coef(mfit), 5.5, 6.2)
也许您的模型在使用更真实的数据时会表现得更好。我希望如此...
我试图在某些预测值周围获得 95% 的置信区间,但我无法实现。
基本上,我估计的增长曲线是这样的:
set.seed(123)
dat=data.frame(size=rnorm(50,10,3),age=rnorm(50,5,2))
S <- function(t,ts,C,K) ((C*K)/(2*pi))*sin(2*pi*(t-ts))
sommers <- function(t,Linf,K,t0,ts,C)
Linf*(1-exp(-K*(t-t0)-S(t,ts,C,K)+S(t0,ts,C,K)))
model <- nls(size~sommers(age,Linf,K,t0,ts,C),data=dat,
start=list(Linf=10,K=4.7,t0=2.2,C=0.9,ts=0.1))
我有独立的尺寸测量值,我想预测年龄。所以函数的反函数,不是很直接,我是这样计算的:
model.out=coef(model)
S.out <- function(t)
((model.out[[4]]*model.out[[2]])/(2*pi))*sin(2*pi*(t-model.out[[5]]))
sommers.out <- function(t)
model.out[[1]]*(1-exp(-model.out[[2]]*(t-model.out[[3]])-S.out(t)+S.out(model.out[[3]])))
inverse = function (f, lower = -100, upper = 100) {
function (y) uniroot((function (x) f(x) - y), lower = lower, upper = upper)[1]
}
sommers.inverse = inverse(sommers.out, 0, 25)
x= sommers.inverse(10) #this works with my complete dataset, but not with this fake one
虽然这工作正常,但我需要知道围绕此估计值 (x) 的置信区间 (95%)。对于线性模型,例如 "predict(... confidence=)"。我还可以 bootstrap 该函数以某种方式获取与参数关联的分位数(未找到方法),然后使用这些参数的极值来计算可预测的最大值和最小值。但这看起来并不是真正的好方法....
如有任何帮助,我们将不胜感激。
回答后编辑:
所以这有效(在 Ben Bolker 的书中有解释,请参阅答案):
vmat = mvrnorm(1000, mu = coef(mfit), Sigma = vcov(mfit))
dist = numeric(1000)
for (i in 1:1000) {dist[i] = sommers_inverse(9.938,vmat[i,])}
quantile(dist, c(0.025, 0.975))
根据我提供的相当糟糕的假数据,这当然很糟糕。但是在真实数据上(我在重新创建时遇到问题),这没问题!
除非我弄错了,否则您将不得不使用常规(参数)自举或称为 "population predictive intervals" 的方法(例如,参见 chapter 7 of Bolker 2008 的第 5 节),这假设您的参数的抽样分布是多元正态分布。但是,我认为你可能有更大的问题,除非我在调整它时以某种方式搞砸了你的模型......
生成数据(注意随机数据实际上可能不利于测试您的模型 - 见下文...)
set.seed(123)
dat <- data.frame(size=rnorm(50,10,3),age=rnorm(50,5,2))
S <- function(t,ts,C,K) ((C*K)/(2*pi))*sin(2*pi*(t-ts))
sommers <- function(t,Linf,K,t0,ts,C)
Linf*(1-exp(-K*(t-t0)-S(t,ts,C,K)+S(t0,ts,C,K)))
绘制数据和初始曲线估计值:
plot(size~age,data=dat,ylim=c(0,16))
agevec <- seq(0,10,length=1001)
lines(agevec,sommers(agevec,Linf=10,K=4.7,t0=2.2,ts=0.1,C=0.9))
我在使用 nls
时遇到了麻烦,所以我使用了 minpack.lm::nls.lm
,它稍微稳健一些。 (这里还有其他选项,例如计算导数和提供梯度函数,或使用 AD Model Builder 或 Template Model Builder,或使用 nls2
包。)
对于nls.lm
我们需要一个函数returns残差:
sommers_fn <- function(par,dat) {
with(c(as.list(par),dat),size-sommers(age,Linf,K,t0,ts,C))
}
library(minpack.lm)
mfit <- nls.lm(fn=sommers_fn,
par=list(Linf=10,K=4.7,t0=2.2,C=0.9,ts=0.1),
dat=dat)
coef(mfit)
## Linf K t0 C ts
## 10.6540185 0.3466328 2.1675244 136.7164179 0.3627371
这是我们的问题:
plot(size~age,data=dat,ylim=c(0,16))
lines(agevec,sommers(agevec,Linf=10,K=4.7,t0=2.2,ts=0.1,C=0.9))
with(as.list(coef(mfit)), {
lines(agevec,sommers(agevec,Linf,K,t0,ts,C),col=2)
abline(v=t0,lty=2)
abline(h=c(0,Linf),lty=2)
})
这种拟合,反函数的结果会极度不稳定,因为反函数是多对一的,反函数的个数值敏感地取决于参数值...
sommers_pred <- function(x,pars) {
with(as.list(pars),sommers(x,Linf,K,t0,ts,C))
}
sommers_pred(6,coef(mfit)) ## s(6)=9.93
sommers_inverse <- function (y, pars, lower = -100, upper = 100) {
uniroot(function(x) sommers_pred(x,pars) -y, c(lower, upper))$root
}
sommers_inverse(9.938, coef(mfit)) ## 0.28
如果我选择间隔非常,我可以得到正确答案...
sommers_inverse(9.938, coef(mfit), 5.5, 6.2)
也许您的模型在使用更真实的数据时会表现得更好。我希望如此...