Estou tentando ajustar uma função de decaimento exponencial aos valores y que se tornam negativos em valores x altos, mas não consigo configurar minha nls
função corretamente.
Alvo
Estou interessado na inclinação da função decay ( acordo com algumas fontes ). Como obtenho essa inclinação não é importante, mas o modelo deve ajustar meus dados da melhor maneira possível (por exemplo, linearizar o problema é aceitável , se o ajuste for bom; consulte "linearização"). No entanto, trabalhos anteriores sobre esse tópico usaram a seguinte função de decaimento exponencial ( artigo de acesso fechado de Stedmon et al., Equação 3 ):
onde S
está a inclinação em que estou interessado, K
o fator de correção para permitir valores negativos e a
o valor inicial para x
(ou seja, interceptação).
Preciso fazer isso em R, pois estou escrevendo uma função que converte medidas brutas da matéria orgânica dissolvida cromofórica (CDOM) em valores nos quais os pesquisadores estão interessados.
Dados de exemplo
Devido à natureza dos dados, tive que usar o PasteBin. Os dados de exemplo estão disponíveis aqui .
Escreva dt <-
e copie o código do PasteBin no seu console R. Ou seja,
dt <- structure(list(x = ...
Os dados são assim:
library(ggplot2)
ggplot(dt, aes(x = x, y = y)) + geom_point()
Valores y negativos ocorrem quando .
Tentando encontrar solução usando nls
A tentativa inicial de usar nls
produz uma singularidade, o que não deve ser uma surpresa, pois acabei de observar os valores iniciais dos parâmetros:
nls(y ~ a * exp(-S * x) + K, data = dt, start = list(a = 0.5, S = 0.1, K = -0.1))
# Error in nlsModel(formula, mf, start, wts) :
# singular gradient matrix at initial parameter estimates
Após esta resposta , posso tentar definir parâmetros de início melhores para ajudar a nls
função:
K0 <- min(dt$y)/2
mod0 <- lm(log(y - K0) ~ x, data = dt) # produces NaNs due to the negative values
start <- list(a = exp(coef(mod0)[1]), S = coef(mod0)[2], K = K0)
nls(y ~ a * exp(-S * x) + K, data = dt, start = start)
# Error in nls(y ~ a * exp(-S * x) + K, data = dt, start = start) :
# number of iterations exceeded maximum of 50
A função parece não conseguir encontrar uma solução com o número padrão de iterações. Vamos aumentar o número de iterações:
nls(y ~ a * exp(-S * x) + K, data = dt, start = start, nls.control(maxiter = 1000))
# Error in nls(y ~ a * exp(-S * x) + K, data = dt, start = start, nls.control(maxiter = 1000)) :
# step factor 0.000488281 reduced below 'minFactor' of 0.000976562
Mais erros. Chuck it! Vamos forçar a função a nos dar uma solução:
mod <- nls(y ~ a * exp(-S * x) + K, data = dt, start = start, nls.control(maxiter = 1000, warnOnly = TRUE))
mod.dat <- data.frame(x = dt$x, y = predict(mod, list(wavelength = dt$x)))
ggplot(dt, aes(x = x, y = y)) + geom_point() +
geom_line(data = mod.dat, aes(x = x, y = y), color = "red")
Bem, essa definitivamente não era uma boa solução ...
Linearizando o problema
Muitas pessoas linearizaram suas funções de decaimento exponencial com sucesso (fontes: 1 , 2 , 3 ). Nesse caso, precisamos garantir que nenhum valor de y seja negativo ou 0. Vamos tornar o valor mínimo de y o mais próximo possível de 0 dentro dos limites de ponto flutuante dos computadores :
K <- abs(min(dt$y))
dt$y <- dt$y + K*(1+10^-15)
fit <- lm(log(y) ~ x, data=dt)
ggplot(dt, aes(x = x, y = y)) + geom_point() +
geom_line(aes(x=x, y=exp(fit$fitted.values)), color = "red")
Muito melhor, mas o modelo não rastreia os valores y perfeitamente em valores x baixos.
Observe que a nls
função ainda não conseguiu ajustar o decaimento exponencial:
K0 <- min(dt$y)/2
mod0 <- lm(log(y - K0) ~ x, data = dt) # produces NaNs due to the negative values
start <- list(a = exp(coef(mod0)[1]), S = coef(mod0)[2], K = K0)
nls(y ~ a * exp(-S * x) + K, data = dt, start = start)
# Error in nlsModel(formula, mf, start, wts) :
# singular gradient matrix at initial parameter estimates
Os valores negativos são importantes?
Os valores negativos são obviamente um erro de medição, pois os coeficientes de absorção não podem ser negativos. E se eu fizer os valores y generosamente positivos? É no declive que me interessa. Se a adição não afeta o declive, eu devo decidir:
dt$y <- dt$y + 0.1
fit <- lm(log(y) ~ x, data=dt)
ggplot(dt, aes(x = x, y = y)) + geom_point() + geom_line(aes(x=x, y=exp(fit$fitted.values)), color = "red")
Bem, isso não foi tão bem ... Valores altos de x devem obviamente ser o mais próximo possível de zero.
A questão
Obviamente, estou fazendo algo errado aqui. Qual é a maneira mais precisa de estimar a inclinação para uma função de decaimento exponencial ajustada em dados que possuem valores y negativos usando R?
nls
convergiu para mim usando os valores iniciais . Alternativamente, você pode usar a função de auto-partida: . Isso converge para mim também.nls(y~SSasymp(x, Asym, r0, lrc), data = dt)