Modelos não lineares permitem o ajuste de relações mais complexas que relações lineares ou linearizáveis entre quantidades de interesse. Em muitos casos tais modelos tem a sua forma funcional específica para o problema sendo tratado, relacionada a algum mecanismo (biológico, físico, etc) inerente ao processo em questão.
Nesta seção vamos ilustrar com dados da área de física de solos o ajuste de modelos não lineares utilizando a função \(\texttt{nls()}\), cujo é um acrônimo para non-linear least squares. Esta função é bastante flexível e incorpora diversas opções para fazer ajustes incluindo características do modelo, tipo e controle dos algorítmos disponíveis.
Diferentemente dos modelos lineares, o ajuste de modelos não lineares não permite que as expressões dos estimadores dos parâmetros desconhecidos do modelo sejam obtidas analiticamente sendo portanto necessário o uso de métodos númericos. Inicialmente mostramos um ajuste feito de forma “ingênua” (naïve), declarando apenas a função e valores iniciais. Tal procedimento, embora simples, pode se ineficiente para o uso de métodos numéricos. Entretanto, o ajuste com \(\texttt{nls()}\) pode incorporar procedimentos que tendem a aprimorar o comportamento dos métodos numéricos tais como o fornecimento de funções que informem sobre a derivada do modelo sendo ajustado, inicialização automática com valores iniciais obtidos automaticamente, linearização parcial do modelo, além da escolha e calibragem dos algorítmos. O objetivo destas notas não é o de investigar todas estas opções, mas apenas fornecer os elementos iniciais para ilustrar a possibilidade de se obter tais resultados usando o \(\texttt{R}\).
Este exemplo mostra o ajuste de um modelo não linear. Primeiro discutimos como efetuar um único ajuste para um conjunto de dados e algumas sugestões para examinar resultados. Ao final mostramos como efetuar vários ajustes de uma só vez de forma eficiente e extrair alguns resultados de particular interesse.
O exemplo mostrado aqui foi motivado por um questão levantada pelo Prof. Álvaro Pires da Silva do Departamento de Ciência do Solo da ESALQ/USP e refere-se ao ajuste da equação de van Genutchen para a curva de retenção de água no solo (ou curva de retenção de água no solo).
Informalmente falando, a equação de van Genutchen é um dos modelos matemáticos utilizados para descrever a curva característica de água no solo que caracteriza a armazenagem de água através de relação entre a umidade e o potencial matricial. Para determinação da curva característica de água o procedimento usual é o de se tomar uma amostra que é submetida a diferentes tensões em condições de laboratório. Para cada tensão aplicada a amostra perde parte do conteúdo de água e mede-se a umidade residual na amostra. A partir dos pares pontos com valores medidos de tensão e umidade, obtem-se a curva de retenção de água no solo que descreve a variação da umidade em função dos valores de tensão. O modelo de van Genutchen é dado pela seguinte equação:
\[ \theta = \theta_{R} + (\theta_{S} - \theta_{R}) \left[ \frac{1}{1 + (\alpha \Psi_{m})^{n}} \right]^{1 - (1/n)} \]
em que \(\Psi_{m}\) é o potencial matricial aplicado à amostra e \(\theta\) é a umidade volumétrica medida na amostra. O parâmetros desconhecidos do modelo modelo são \(\theta_{S}\) e \(\theta_{R}\) que correspondem à umidade volumétrica na saturação e residual, respectivamente, \(\alpha\) e \(n\) que definem o formato da curva sendo que o primeiro representa o inverso do potencial de entrada de ar e o segundo é um índice da distribuição dos tamanhos de poros. Portanto são obtidos dados para os pares de pontos \((\Psi_{m}, \theta)\) e \((\theta_{S}, \theta_{R}, \alpha, n)\) são parâmetros desconhecidos a serem estimados e que caracterizam a curva de retenção.
Para exemplificar o ajuste utilizamos dados cedidos pelo Prof. Álvaro que podem ser obtidos usando o comando mostrado a seguir. Este conjunto de dados refere-se a apenas duas amostras que são um subconjunto dos dados originais que contém diversas amostras. O objetivo é determinar da curva de retenção de água no solo estimada segundo modelo de van Genutchen para cada uma das amostras. No objeto \(\texttt{cra}\) a primeira coluna (\(\texttt{am}\)) indica o número da amostra, a segunda (\(\texttt{pot}\)) o potencial aplicado e a terceira (\(\texttt{u}\)) a umidade do solo. Vemos a seguir que dispomos de 15 pontos medidos da curva de retenção da primeira amostra e 13 para a segunda.
cra <- read.table("http://www.leg.ufpr.br/~paulojus/dados/cra.csv",
header = TRUE,
sep = ",")
head(cra)
am pot u
1 30 10 0.3071
2 30 19 0.2931
3 30 30 0.2828
4 30 45 0.2753
5 30 63 0.2681
6 30 64 0.2628
cra <- transform(cra,
am = as.factor(am))
summary(cra)
am pot u
30:15 Min. : 10.0 Min. :0.0636
41:13 1st Qu.: 58.5 1st Qu.:0.1199
Median : 107.5 Median :0.1969
Mean : 2139.8 Mean :0.1879
3rd Qu.: 1550.0 3rd Qu.:0.2436
Max. :26300.0 Max. :0.3071
Inicialmente vamos nos concentrar na discussão do ajuste do modelo e para isto, vamos isolar os dados referentes a uma única amostra.
(cra30 <- subset(cra,
am == 30))
am pot u
1 30 10 0.3071
2 30 19 0.2931
3 30 30 0.2828
4 30 45 0.2753
5 30 63 0.2681
6 30 64 0.2628
7 30 75 0.2522
8 30 89 0.2404
9 30 105 0.2272
10 30 138 0.2120
11 30 490 0.1655
12 30 3000 0.1468
13 30 4100 0.1205
14 30 5000 0.1013
15 30 26300 0.0730
No gráfico à esquerda visualizamos os dados de umidade versus pressão aplicada na amostra.
Uma melhor visualização é obtida utilizando-se no eixo horizontal o logarítmo (base 10) dos valores das pressões aplicadas conforme mostrado no gráfico à direita.
g1 <- xyplot(u ~ pot,
type = c("p", "g"),
pch = 16,
xlab = expression(Psi[m]),
ylab = list(label = expression(theta),
rot = 0),
ylim = c(0, .35),
scales = list(x = list(rot = 30)),
cra30)
g2 <- xyplot(u ~ log10(pot),
type = c("p", "g"),
pch = 16,
xlab = expression(log[10](Psi[m])),
ylab = list(label = expression(theta),
rot = 0),
ylim = c(0, .35),
scales = list(x = list(tick.number = 6,
rot = 30)),
cra30)
print(g1,
position = c(0, 0,
.5, 1),
more = TRUE)
print(g2,
position = c(.5, 0,
1, 1))
Portanto, os dados nas colunas \(\texttt{u}\) e \(\texttt{pot}\) do objeto de dados correspondem à \(\theta\) e \(\Psi_{m}\), e as demais quantidades \((\theta_{R},\theta_{S}, n, \alpha)\) são parâmetros (coeficientes) a serem estimados a partir do ajuste do modelo teórico aos dados. Este é um modelo não linear e pode ser ajustado utilizando o método de mínimos quadrados conforme implementado na \(\texttt{nls()}\).
A função possui três argumentos obrigatórios: (i) o primeiro é utilizado para declarar a expressão do modelo a ser ajustado, (ii) o segundo informa o objeto contendo o conjunto de dados cujas nomes das colunas relevantes devem ter o mesmo nome utilizado na declaração do modelo e, (iii) valores iniciais para os parâmetros a serem ajustados que devem ser passados por uma named list, isto é, uma lista com nomes dos elementos, e estes nomes também devem coincidir com os utilizados na declaração do modelo. Há argumentos adicionais para controlar o comportamento algorítimo, tal como critério de convergência. A documentação de \(\texttt{nls()}\) fornece mais detalhes.
A escolha dos valores iniciais é crucial e pode influenciar nos resultados do ajuste utilizando métodos numéricos, especialmente em exemplos como este com um pequeno número de dados. Os valores iniciais para \(\theta_{S}\) e \(\theta_{R}\) foram escolhidos inspecionando-se o gráfico e considerando a interpretação destes como valores de saturação e residual de umidade, portanto, considerando-se máximos e mínimos assintóticos para a função. A escolha de valores iniciais para os demais parâmetros é menos óbvia. Uma das formas de se obter tais valores é efetuar um ajuste aproximado, visual por tentativa e erro, traçando-se curvas sobre o gráfico dos dados. O comando a seguir ilustra como fazer tal procedimento a partir do gráfico dos dados originais mostrado anteriormente definindo uma expressão com o modelo de van Genutchen. Os valores foram escolhidos após uma séria de tentativas.
xyplot(u ~ pot,
type = c("p", "g"),
pch = 16,
xlab = expression(Psi[m]),
ylab = list(label = expression(theta),
rot = 0),
ylim = c(0, .35),
scales = list(x = list(rot = 30)),
cra30) +
layer(panel.curve(.05 + (.35 - .05) / ( (1 + (.1 * x) ^ 1.3) ^ (1 - 1 / 1.3) ),
lty = 2))
Definidos os valores iniciais prossegue-se com o ajuste do modelo conforme os comandos a seguir.
fit30 <- nls(u ~ ur + (us - ur) / ( (1 + (alpha * pot) ^ n) ^ (1 - 1 / n) ),
start = list(us = .35,
ur = .05,
alpha = .1,
n = 1.3),
data = cra30)
summary(fit30)
Formula: u ~ ur + (us - ur)/((1 + (alpha * pot)^n)^(1 - 1/n))
Parameters:
Estimate Std. Error t value Pr(>|t|)
us 0.324121 0.017744 18.27 1.41e-09 ***
ur 0.007082 0.071084 0.10 0.922
alpha 0.038780 0.026202 1.48 0.167
n 1.211816 0.105207 11.52 1.77e-07 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.01104 on 11 degrees of freedom
Number of iterations to convergence: 8
Achieved convergence tolerance: 7.004e-06
A partir do modelo ajustado pode-se calcular quantidades de interesse. Neste particular exemplo calculamos uma quantidade de interesse prática denotada por \(S\) que é um indicador da qualidade física do solo. Quanto maior o valor de \(S\), melhor a sua qualidade física.
(S <- with(as.list(coefficients(fit30)),
abs((- n * (us - ur) * ( ( (2 * n - 1) / (n - 1) ) ^ (1 / n - 2) ) ))))
[1] 0.04097126
Os valores preditos são obtidos de forma direta com \(\texttt{fitted(fit30)}\) ou \(\texttt{predict(fit30)}\). Para visualização e avaliação do modelo ajustado podemos fazer diferentes gráficos. A Figura abaixo mostra os pontos ajustados no gráfico da esquerda, e a união destes pontos no gráfico da direita. Gráficos de resíduos semelhantes aos obtidos para avaliar ajuste de modelos lineares podem e devem também ser investivados em uma análise. Neste exemplo mostramos o qq-plot dos resíduos e o gráfico dos resíduos versus valores preditos.
g1 <- xyplot(u ~ log10(pot),
type = c("p", "g"),
pch = 16,
cex = .8,
xlab = expression(log[10](Psi)),
ylab = list(label = expression(theta(Umidade, g/g)),
rot = 0),
scale = list(x = list(tick.number = 6)),
cra30,
key = list(corner = c(1, .97),
text = list(c("observado",
"ajustado")),
points = list(col = c("dodgerblue2", 2),
cex = .8,
pch = c(16, 3)))) +
as.layer(xyplot(fitted(fit30) ~ log10(pot),
col = 2,
pch = 3,
cex = .8,
cra30))
g2 <- xyplot(u ~ log10(pot),
type = c("p", "g"),
pch = 16,
cex = .8,
xlab = expression(log[10](Psi[m])),
ylab = list(label = expression(theta(Umidade, g/g)),
rot = 0),
scale = list(x = list(tick.number = 6)),
cra30,
key = list(corner = c(1, .97),
text = list(c("observado",
"ajustado")),
points = list(col = c("dodgerblue2", 2),
cex = .8,
pch = c(16, 3)))) +
as.layer(xyplot(fitted(fit30) ~ log10(pot),
type = "b",
col = 2,
pch = 3,
cex = .8,
cra30))
rs <- residuals(fit30)
g3 <- qqmath(rs,
type = c("p", "g"),
pch = 16,
xlab = "Quantis teóricos",
ylab = list(label = "Quantis \n amostrais",
rot = 0)) +
layer(panel.qqmathline(rs,
col = "dodgerblue2"))
g4 <- xyplot(rs ~ fitted(fit30),
type = c("p", "g"),
pch = 16,
cex = .8,
xlab = "Valores ajustados",
ylab = list(label = "Resíduos",
rot = 0)) +
layer(panel.abline(h = 0,
col = "navy",
lwd = 1.5))
print(g1,
position = c(0, .5,
.5, 1),
more = TRUE)
print(g2,
position = c(.5, .5,
1, 1),
more = TRUE)
print(g3,
position = c(0, 0,
.5, .5),
more = TRUE)
print(g4,
position = c(.5, 0,
1, .5))
Para obter uma melhor visualização do modelo ajustado pode-se obter valores na curva ajustada não apenas nos pontos observados, mas em uma sequência de valores ao longo do gráfico como ilustrado a seguir. A Figura à esquerda mostra o modelo definido pelos valores iniciais e o modelo ajustado na escala original. Note que neste exemplo em geral prefere-se a visualização na escala logarítmica do potencial conforme o gráfico da direita. A curva com o modelo ajustado a serem desenhadas sobre o gráfico dos dados são obtidas com comandos a seguir.
pp <- 10 ^ seq(1, 4.5,
length.out = 201)
g1 <- xyplot(u ~ pot,
type = c("p", "g"),
pch = 16,
xlab = expression(Psi[m]),
ylab = list(label = expression(theta),
rot = 0),
ylim = c(0, .35),
scales = list(x = list(rot = 30)),
key = list(corner = c(1, .97),
text = list(c("valores iniciais",
"valores ajustados")),
lines = list(col = c(1, "dodgerblue2"),
lty = 2:1)),
cra30) +
layer(panel.curve(.05 + (.35 - .05) / ( (1 + (.1 * x) ^ 1.3) ^ (1 - 1 / 1.3) ),
lty = 2)) +
layer(panel.lines(pp, predict(fit30, list(pot = pp))))
g2 <- xyplot(u ~ log10(pot),
type = c("p", "g"),
pch = 16,
cex = .8,
xlab = expression(log[10](Psi[m])),
ylab = list(label = expression(theta),
rot = 0),
scale = list(x = list(tick.number = 6,
rot = 30)),
cra30) +
layer(panel.lines(log10(pp), predict(fit30, list(pot = pp))))
print(g1,
position = c(0, 0,
.5, 1),
more = TRUE)
print(g2,
position = c(.5, 0,
1, 1))
Comentários: é importante lembrar que certos modelos não lineares são parcialmente linearizáveis e neste caso o ajuste pode ser mais preciso e numericamente estável se beneficiando disto para reduzir a dimensão do problema de otimização numérica. Para isto é necessário redefinir a especicifação do modelo e utilizar o argumento \(\texttt{method= " plinear"}\) na \(\texttt{nls()}\). Neste exemplo em particilar pode-se considerar fazer o ajuste na escala de \(log_{10}(\Psi_{m})\) já que os resultados são tipicamente visualizados desta forma. Isto reduz a escala dos valores das variáveis e também torna o problema mais estável numericamente. Por outro lado, em geral reparametrizações podem mudar a interpretação de alguns parâmetros de modelo. Finalmente cuidados usuais com ajuste de modelos utilizando métodos iterativos devem ser observados, tais como sensibilidade a valores iniciais e verificação de convergência do algorítmo numérico.
Vamos considerar uma situação comum na prática onde em geral tem-se várias amostras para as quais deseja-se fazer ajustes individuais como ilustrado anteriormente. É portanto conveniente que isto seja feito de forma automática, sem a necesidade de repetir os passos acima a cada ajuste. Neste exemplo vamos considerar duas amostras, mas o procedimento demostrado a seguir é geral e funcionará igualmente para um maior número de amostras.
Serão mostradas duas soluções. Nesta sessão o ajuste é feito para cada amostra individualmente automatizando várias chamadas da função \(\texttt{nls()}\) através do \(\texttt{lapply()}\) emulando o comportamento das várias chamadas em um loop. Na próxima sessão será mostrado como obter os todos os ajustes com uma única chamada da \(\texttt{nls()}\). Ilustramos ambos os casos porque a forma mais adequada vai depender de situação em questão e dos objetivos da análise.
Começamos definindo uma função que contém uma chamada da \(\texttt{nls()}\), como acima. Nesta função estamos incluindo um argumento \(\texttt{ini}\) para passar valores iniciais que caso não fornecido assumirá os valores indicados. A seguir utilizamos a função \(\texttt{by()}\) para proceder o ajuste para cada amostra individualmente. Esta função retorna uma lista com dois elementos, um para cada amostra, sendo que cada um deles contém o ajuste do modelo não linear.
fit.vG <- function(x, ini = list(us = .3,
ur = .02,
alpha = .05,
n = 1.3))
nlsfit <- nls(u ~ ur + (us - ur) / (1 + (alpha * pot) ^ n) ^ (1 - 1 / n),
start = ini,
data = x)
allfits <- by(cra, cra$am, fit.vG)
names(allfits)
[1] "30" "41"
Neste caso, o objeto resultante \(\texttt{allfits}\) é uma lista de listas e portanto podemos usar funções como \(\texttt{lapply()}\), \(\texttt{sapply()}\) ou similares para extrair resultados de interesse. Note que a primeira retorna sempre uma lista, enquanto que a segunda “simplifica” o objeto resultante se possível. Por exemplo, quando extraindo coeficientes a função retorna uma matrix 4 × 2, já que para cada uma das duas amostras são extraidos quatro coeficientes.
lapply(allfits, summary)
$`30`
Formula: u ~ ur + (us - ur)/(1 + (alpha * pot)^n)^(1 - 1/n)
Parameters:
Estimate Std. Error t value Pr(>|t|)
us 0.324120 0.017744 18.27 1.41e-09 ***
ur 0.007082 0.071084 0.10 0.922
alpha 0.038780 0.026202 1.48 0.167
n 1.211816 0.105207 11.52 1.77e-07 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.01104 on 11 degrees of freedom
Number of iterations to convergence: 6
Achieved convergence tolerance: 7.997e-06
$`41`
Formula: u ~ ur + (us - ur)/(1 + (alpha * pot)^n)^(1 - 1/n)
Parameters:
Estimate Std. Error t value Pr(>|t|)
us 0.243148 0.009446 25.741 9.71e-10 ***
ur -0.122402 0.171615 -0.713 0.494
alpha 0.035928 0.022324 1.609 0.142
n 1.113320 0.079473 14.009 2.04e-07 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.006207 on 9 degrees of freedom
Number of iterations to convergence: 7
Achieved convergence tolerance: 9.457e-06
lapply(allfits, coef)
$`30`
us ur alpha n
0.324120323 0.007082248 0.038779880 1.211816160
$`41`
us ur alpha n
0.24314784 -0.12240201 0.03592828 1.11332042
sapply(allfits, coef)
30 41
us 0.324120323 0.24314784
ur 0.007082248 -0.12240201
alpha 0.038779880 0.03592828
n 1.211816160 1.11332042
Quando ajustamos o modelo apenas para uma das amostras mostramos como calcular o índice \(S\) de qualidade física do solo a partir dos coeficientes estimados. Vamos então aqui obter este índice para cada uma das amostras. Para isto simplesmente definimos uma função que recebe o modelo ajustado e usa os coeficiente para calcular o valor de \(S\). Passamos o objeto (lista) contendo todos os ajustes e a função que calcula \(S\) para \(\texttt{sapply()}\) que neste caso vai simplificar o resultado para formato de um vetor, já que a função calculaS retorna um escalar para cada amostra.
calculaS <- function(fit)
with(as.list(coef(fit)), abs((- n * (us - ur) * ( ( (2 * n - 1) / (n - 1) ) ^ (1 / n - 2) ))))
(Sall <- sapply(allfits, calculaS))
30 41
0.04097127 0.02950320
Finalmente, para encerrar este exemplo, vamos mostrar uma possível forma de combinar a visualização dos ajustes em um único gráfico. Começamos definindo uma sequência de valores para os quais queremos visualizar os ajustes. Armazenamos os valores preditos para cada amostra no objeto \(\texttt{allpred}\) e optamos aqui por mostrar os ajustes para as duas amostras no mesmo gráfico.
lpsimax <- with(cra, max(log(pot)))
pp <- 10 ^ seq(1, lpsimax,
length.out = 501)
allpred <- lapply(allfits, predict, list(pot = pp))
xyplot(u ~ log10(pot),
type = c("n", "g"),
xlab = expression(log[10](Psi)),
ylab = list(label = expression(theta(Umidade, g/g)),
rot = 0),
scale = list(x = list(tick.number = 6)),
cra) +
layer(with(cra, panel.text(log10(pot), u, as.character(am), cex = .75))) +
layer(lapply(allpred, function(yp)
llines(log10(pp), yp)))
Na sessão anterior obtivemos o ajusta para cada amostra separadamente fazendo várias chamadas à função \(\texttt{nls()}\). Isto pode ser adequado quando deseja-se de fato ajustes individuais e se, por um lado são efetuadas várias chamadas à função, por outro o número de dados em cada uma delas é pequeno. Uma forma alternativa de obter parâmetros para cada amostra, e talvez mais eficiente que a mostrada anteriormente é discutida a seguir.
Nesta sessão vamos considerar fazer todos os ajustes de só vez, isto é em uma única chamada da \(\texttt{nls()}\) que portanto vai utilizar todos os dados de todas as amostras. Além do aspecto computacional, isto pode ser interessante pois permite comparar e testar hipóteses para escolha entre diferentes modelos alternativos para explicar os dados. Exemplificamos tal procedimento a seguir iniciando com um modelo para cada amostra e comparando com um modelo que assume que os parâmetros \((\alpha, n)\) são comuns entre as amostras. Neste caso interpreta-se que cada amostra informa sobre os respectivos valores para \((\theta_{S}, \theta_{R})\) enquanto que todas as amostras conjuntamente informam sobre \((\alpha, n)\). Após ajustar os modelos “candidatos” podemos fazer uma comparação formal dos ajustes através da \(\texttt{anova()}\), o que não seria possível ajustando os modelos separadamente como mostrado sessão anterior. Os dois ajustes são mostrados a seguir, o seletor \([]\) é usado para indicar que os dados são tratados em grupos definidos por \(\texttt{am}\). No caso do modelo com parâmetros distintos informamos oito valores iniciais para os parâmetros.
(mod0 <- nls(u ~ ur[am] + (us[am] - ur[am]) * ( 1 / ( 1 + (alpha[am] * pot) ^ n[am] ) ) ^ (1 - 1 / n[am]),
start = list(us = c(.3, .3),
ur = c(0, 0),
alpha = c(.04, .04),
n = c(1.25, 1.25)),
cra))
Nonlinear regression model
model: u ~ ur[am] + (us[am] - ur[am]) * (1/(1 + (alpha[am] * pot)^n[am]))^(1 - 1/n[am])
data: cra
us1 us2 ur1 ur2 alpha1 alpha2 n1
0.324120 0.243148 0.007085 -0.122402 0.038779 0.035928 1.211820
n2
1.113320
residual sum-of-squares: 0.001688
Number of iterations to convergence: 6
Achieved convergence tolerance: 4.637e-06
Para ajuste assumindo valores comuns para os parâmetros \(\alpha\) e \(n\) não utilizamos o indicados de grupos para estes parâmetros e informamos apenas um valor inicial para cada um deles.
(mod1 <- nls(u ~ ur[am] + (us[am] - ur[am]) * ( 1 / ( 1 + (alpha * pot) ^ n ) ) ^ ( 1 - 1 / n ),
start = list(us = c(.3, .3),
ur = c(0, 0),
alpha = .04,
n = 1.25),
cra))
Nonlinear regression model
model: u ~ ur[am] + (us[am] - ur[am]) * (1/(1 + (alpha * pot)^n))^(1 - 1/n)
data: cra
us1 us2 ur1 ur2 alpha n
0.32106 0.24870 -0.03056 -0.02759 0.03994 1.17195
residual sum-of-squares: 0.001846
Number of iterations to convergence: 5
Achieved convergence tolerance: 2.012e-06
Neste exemplo temos então um modelo inicial com oito e outro mais parcimonioso com apenas seis parâmetros e utilizamos um teste formal para orientar a escolha de modelo, que neste caso indica que o modelo mais parcimonioso com parâmetros comuns explica os dados satisfatóriamente.
anova(mod1, mod0)
Analysis of Variance Table
Model 1: u ~ ur[am] + (us[am] - ur[am]) * (1/(1 + (alpha * pot)^n))^(1 - 1/n)
Model 2: u ~ ur[am] + (us[am] - ur[am]) * (1/(1 + (alpha[am] * pot)^n[am]))^(1 - 1/n[am])
Res.Df Res.Sum Sq Df Sum Sq F value Pr(>F)
1 22 0.0018462
2 20 0.0016884 2 0.00015786 0.935 0.4091