1 Definições da sessão

#-----------------------------------------------------------------------
#                                            Prof. Dr. Walmes M. Zeviani
#                                leg.ufpr.br/~walmes · github.com/walmes
#                                        walmes@ufpr.br · @walmeszeviani
#                      Laboratory of Statistics and Geoinformation (LEG)
#                Department of Statistics · Federal University of Paraná
#                                       2021-mar-04 · Curitiba/PR/Brazil
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# Pacotes.

rm(list = objects())

library(tidyverse)
library(nlme)

2 Importação e preparo

#-----------------------------------------------------------------------
# Importação e preparo.

# Importação.
da <- read.table(file = "BD.txt", header = TRUE, sep = "\t")
str(da)
## 'data.frame':    4971 obs. of  2 variables:
##  $ gro: int  1 1 1 1 1 1 1 1 1 1 ...
##  $ dbh: num  362.9 82.8 89.1 82.8 30 ...
# Preparo.
da <- da %>%
    mutate(gro = factor(gro),
           dbh = dbh/10) %>%
    drop_na()

# %>%
#     filter(dbh >= 10)

# Gráfico de densidade.
ggplot(data = da,
       mapping = aes(x = dbh)) +
    facet_wrap(facets = ~gro) +
    # scale_x_log10() +
    geom_density()

# Gráfico de distribuição acumulada.
ggplot(data = da,
       mapping = aes(x = dbh)) +
    facet_wrap(facets = ~gro) +
    # scale_x_log10() +
    stat_ecdf()

3 Ajuste da distribuição Weibull 2 parâmetros por máxima verossimilhança

#-----------------------------------------------------------------------
# Ajuste das curvas por máxima verossimilhança.

# Cria o log.
da <- da %>%
    mutate(ldbh = log10(dbh))

# Ajuste.
ll_fit <- da %>%
    group_by(gro) %>%
    do({
        fit <- MASS::fitdistr(na.omit(.$dbh), densfun = "weibull")
        fit$estimate %>%
            as.list() %>%
            as.data.frame()
    }) %>%
    ungroup()
ll_fit
## # A tibble: 4 x 3
##   gro   shape scale
##   <fct> <dbl> <dbl>
## 1 1     0.880  3.74
## 2 2     1.01   4.10
## 3 3     0.983  3.75
## 4 4     1.08   4.54
# Valor máximo para fazer a predição.
max_val <- max(da$dbh, na.rm = TRUE)

# Cria valores para plotar a distribuição ajustada.
fit_curves <- ll_fit %>%
    group_by(gro) %>%
    do({
        x <- seq(0, max_val, length.out = 201)
        fy <- dweibull(x, shape = .$shape, scale = .$scale)
        Fy <- pweibull(x, shape = .$shape, scale = .$scale)
        data.frame(dbh = x, fy = fy, Fy = Fy)
    }) %>%
    ungroup()
head(fit_curves)
## # A tibble: 6 x 4
##   gro     dbh      fy    Fy
##   <fct> <dbl>   <dbl> <dbl>
## 1 1     0     Inf     0    
## 2 1     0.324   0.281 0.110
## 3 1     0.647   0.235 0.192
## 4 1     0.971   0.204 0.263
## 5 1     1.29    0.180 0.325
## 6 1     1.62    0.161 0.380
# Ajuste na escala acumulada.
ggplot(data = da,
       mapping = aes(x = dbh)) +
    facet_wrap(facets = ~gro) +
    # scale_x_log10() +
    stat_ecdf() +
    geom_line(data = fit_curves,
              mapping = aes(x = dbh, y = Fy),
              color = "red",
              inherit.aes = TRUE)

# Ajuste na escala da densidade.
ggplot(data = da,
       mapping = aes(x = dbh)) +
    facet_wrap(facets = ~gro) +
    geom_density() +
    geom_line(data = fit_curves,
              mapping = aes(x = dbh, y = fy),
              color = "red",
              inherit.aes = TRUE)

4 Obtenção da ECDF para ajuste da Weibull via mínimos quadrados

#-----------------------------------------------------------------------
# Fazer a distribuição de valores de diâmetro DENTRO de cada categoria
# para gerar o par (x, Freq_acum(x)) e com isso ajustar o modelo
# Weibull.

# Número de valores distintos e tamanho de amostra.
da %>%
    group_by(gro) %>%
    summarise(n_support = length(unique(dbh)),
              n = n())
## # A tibble: 4 x 3
##   gro   n_support     n
##   <fct>     <int> <int>
## 1 1           823   972
## 2 2          1087  1371
## 3 3          1119  1397
## 4 4           854  1028
# Obtém a ECDF.
tb_freq <- da %>%
    group_by(gro) %>%
    arrange(dbh) %>%
    mutate(frel = 1/n()) %>%
    group_split() %>%
    map(function(tb) {
        ecdf_fun <- ecdf(x = c(tb$dbh))
        u <- unique(tb$dbh)
        data.frame(dbh = u, ecdf = ecdf_fun(u))
    }) %>%
    bind_rows(.id = "gro") %>%
    drop_na()

# Cria o log.
tb_freq <- tb_freq %>%
    mutate(ldbh = log10(dbh))

# Confere.
tb_freq %>%
    group_by(gro) %>%
    summarise_at("ecdf", "max")
## # A tibble: 4 x 2
##   gro    ecdf
##   <chr> <dbl>
## 1 1         1
## 2 2         1
## 3 3         1
## 4 4         1
# NOTE: tudo o que foi feito foi para ter a ECDF!
ggplot(data = tb_freq,
       mapping = aes(x = dbh, y = ecdf)) +
    facet_wrap(facets = ~gro) +
    scale_x_log10() +
    geom_point() +
    stat_ecdf(data = da,
              mapping = aes(x = dbh),
              color = "green",
              inherit.aes = FALSE)

5 Ajuste do modelo não linear de Weibull com efeitos aleatórios

library(rpanel)

source("https://raw.githubusercontent.com/walmes/wzRfun/master/R/rp.nls.R")

m0 <- rp.nls(model = ecdf ~ (1 - exp(-((ldbh - a)/b)^c)) ,
             data = transform(tb_freq, ldbh = log10(dbh)),
             start = list(a = c(-10, 10),
                          b = c(0, 5),
                          c = c(0.01, 10)),
             xlab = "Diâmetros (cm)",
             ylab = "Frequência Relativa Acumulada")
#
#-----------------------------------------------------------------------
# Avaliação dos valores iniciais.

# Valores iniciais.
start <- c(a = -1.9, b = 2.5, c = 6)

# Testa os valores iniciais.
ggplot(data = tb_freq,
       mapping = aes(x = ldbh, y = ecdf)) +
    facet_wrap(facets = ~gro) +
    # scale_x_log10() +
    geom_point() +
    stat_function(color = "red",
                  fun = function(x) {
                      with(as.list(start), {
                          (1 - exp(-((x - a)/b)^c))
                      })
                  })

#-----------------------------------------------------------------------
# Aqui tá sendo feito o ajuste de uma distribuição de probabilidades
# usando as frequências relativas acumuladas em função dos valores
# únicos no suporte e usando mínimos quadrados para ajustar o modelo não
# linear que é a acumulada do modelo de distribuição de
# probabilidades. A abordagem por máxima verossimilhança parece mais
# interessante por várias razões.

# Ajuste do modelo não linear de efeito misto em que todos os
# coeficientes da ECDF de Weibull variam (de efeito aleatório) conforme
# os grupos.

n0 <- nlme(model = ecdf ~ (1 - exp(-((ldbh - a)/b)^c)),
           data = tb_freq,
           fixed = a + b + c ~ 1,
           random = a + b + c ~ 1 | gro,
           start = start)

summary(n0)
## Nonlinear mixed-effects model fit by maximum likelihood
##   Model: ecdf ~ (1 - exp(-((ldbh - a)/b)^c)) 
##  Data: tb_freq 
##         AIC       BIC   logLik
##   -26891.67 -26829.02 13455.83
## 
## Random effects:
##  Formula: list(a ~ 1, b ~ 1, c ~ 1)
##  Level: gro
##  Structure: General positive-definite, Log-Cholesky parametrization
##          StdDev      Corr         
## a        0.082151256 a      b     
## b        0.077366188 -0.846       
## c        0.326555546  0.702 -0.213
## Residual 0.007494148              
## 
## Fixed effects: a + b + c ~ 1 
##        Value  Std.Error   DF   t-value p-value
## a -0.7604386 0.04131663 3877 -18.40515       0
## b  1.2827320 0.03894435 3877  32.93756       0
## c  3.0040540 0.16378444 3877  18.34151       0
##  Correlation: 
##   a      b     
## b -0.847       
## c  0.688 -0.203
## 
## Standardized Within-Group Residuals:
##        Min         Q1        Med         Q3        Max 
## -3.2901534 -0.6848663 -0.0772755  0.5894960  3.7256666 
## 
## Number of Observations: 3883
## Number of Groups: 4
fixef(n0)
##          a          b          c 
## -0.7604386  1.2827320  3.0040540
ranef(n0)
##              a           b           c
## 1 -0.131776645  0.09261088 -0.43700012
## 2 -0.004738264  0.01903766  0.07278539
## 3  0.080141505 -0.12200276 -0.10420081
## 4  0.056373404  0.01035422  0.46841554
# Ajuste do modelo não linear de efeito misto em que apenas os
# coeficientes de forma e escala apresentam efeito aleatório, sendo o
# coeficiente de locação (a) é fixo.

n1 <- nlme(model = ecdf ~ (1 - exp(-((ldbh - a)/b)^c)),
           data = tb_freq,
           fixed = a + b + c ~ 1,
           # random = a + b ~ 1 | gro,
           random = a + c ~ 1 | gro,
           # random = b + c ~ 1 | gro,
           start = fixef(n0))

anova(n0, n1)
##    Model df       AIC       BIC   logLik   Test  L.Ratio p-value
## n0     1 10 -26891.67 -26829.02 13455.83                        
## n1     2  7 -26574.97 -26531.12 13294.49 1 vs 2 322.6936  <.0001
summary(n1)
## Nonlinear mixed-effects model fit by maximum likelihood
##   Model: ecdf ~ (1 - exp(-((ldbh - a)/b)^c)) 
##  Data: tb_freq 
##         AIC       BIC   logLik
##   -26574.97 -26531.12 13294.49
## 
## Random effects:
##  Formula: list(a ~ 1, c ~ 1)
##  Level: gro
##  Structure: General positive-definite, Log-Cholesky parametrization
##          StdDev      Corr 
## a        0.044725958 a    
## c        0.410741139 0.626
## Residual 0.007813012      
## 
## Fixed effects: a + b + c ~ 1 
##       Value  Std.Error   DF   t-value p-value
## a -0.768068 0.02283984 3877 -33.62843       0
## b  1.290104 0.00467111 3877 276.18806       0
## c  3.042440 0.20586229 3877  14.77901       0
##  Correlation: 
##   a      b     
## b -0.201       
## c  0.599  0.062
## 
## Standardized Within-Group Residuals:
##         Min          Q1         Med          Q3         Max 
## -3.48120946 -0.62887776 -0.05188943  0.54638105  4.03215670 
## 
## Number of Observations: 3883
## Number of Groups: 4
fixef(n1)
##         a         b         c 
## -0.768068  1.290104  3.042440
ranef(n1)
##             a            c
## 1 -0.04128617 -0.663469834
## 2  0.01437813  0.002846493
## 3 -0.04006093  0.240018002
## 4  0.06696896  0.420605339
coef(n1)
##            a        b        c
## 1 -0.8093542 1.290104 2.378970
## 2 -0.7536899 1.290104 3.045287
## 3 -0.8081290 1.290104 3.282458
## 4 -0.7010991 1.290104 3.463046
#-----------------------------------------------------------------------
# Fazer a predição das curvas.

extr_val <- extendrange(tb_freq$ldbh)

grid <- crossing(gro = unique(tb_freq$gro),
                 ldbh = seq(extr_val[1],
                            extr_val[2],
                            length.out = 201))
grid$y <- predict(n1, newdata = grid)

# Resultado do ajuste.
ggplot(data = tb_freq,
       mapping = aes(x = ldbh, y = ecdf)) +
    facet_wrap(facets = ~gro) +
    geom_point() +
    geom_line(data = grid,
              mapping = aes(x = ldbh, y = y),
              inherit.aes = FALSE,
              color = "magenta")

# ATTENTION: problemas com a abordagem de mínimos quadrados sobre a
# ECDF.
#
# O tamanho de amostra não é o número de árvores medidas mas sim o
# número de valores únicos de diâmetro. Com isso, dependendo da escala
# do aparelho de medida, pode haver uma diferença bem grande entre as
# quantidades tamanho de amostra e número de valores no suporte. Por
# isso a abordagem de verossimilhança é mais indicada.

#