Search code examples
rtidyversecurve-fitting

How do Irun models over categories of group?


I am trying to model plant decomposition curves using the litterfitter package. My dataset has three columns, time, mass remaining and site code. I want to apply the model over categories of site code and extract the model parameters but am having some difficulty. Below is an example with error codes.

library(litterfitter)
library(tidyverse)

decomp_test <- structure(list(site_code = c("CCPp1a", "CCPp1a", "CCPp1a", "CCPp1a", 
"CCPp1a", "CCPp1b", "CCPp1b", "CCPp1b", "CCPp1b", "CCPp1b", "CCPp1c", 
"CCPp1c", "CCPp1c", "CCPp1c", "CCPp1c", "CCPp1d", "CCPp1d", "CCPp1d", 
"CCPp1d", "CCPp1d", "CCPp1e", "CCPp1e", "CCPp1e", "CCPp1e", "CCPp1e", 
"CCPp1f", "CCPp1f", "CCPp1f", "CCPp1f", "CCPp1f"), days_between = c(0L, 
118L, 229L, 380L, 572L, 0L, 118L, 229L, 380L, 572L, 0L, 118L, 
229L, 380L, 572L, 0L, 118L, 229L, 380L, 572L, 0L, 118L, 229L, 
380L, 572L, 0L, 118L, 229L, 380L, 572L), mass_remaining = c(1, 
0.7587478816, 0.7366473295, 0.6038150404, 0.6339366063, 1, 0.7609346914, 
0.7487194938, 0.7336179508, 0.6595702348, 1, 0.777213425, 0.734006734, 
0.6963752241, 0.5827854154, 1, 0.7716566866, 0.7002094345, 0.6913555798, 
0.7519095328, 1, 0.7403565314, 0.6751289171, 0.6572164948, 0.620339994, 
1, 0.8126440236, 0.7272999401, 0.7223268259, 0.6805293006)), row.names = c(NA, 
-30L), class = "data.frame")

#Test data-frame with a small number of sites

discrete_paralell <-
  decomp_test %>%
  nest(-site_code) %>%
  mutate(fit = map(decomp_test, ~ fit_litter(time=decomp_test$days_between ,mass.remaining= decomp_test$mass_remaining,
                                                model='discrete.parallel',iters=1000)),
         results = map(fit, glance)) %>% 
  unnest(results)

Error: Problem with mutate() column fit. i fit = map(...). i fit must be size 6 or 1, not 3.

#or

discrete_paralell <-
  decomp_test %>%
  nest(-site_code) %>%
  mutate(fit = map(decomp_test, ~ fit_litter(time=decomp_test$days_between ,mass.remaining= decomp_test$mass_remaining,
                                                model='discrete.parallel',iters=1000)),
         coef = map_dbl(fit, "coef"),
         actual = map_dbl(fit, "mass"),
         preds = map_dbl(fit, "predicted"),
         AIC = map_dbl(fit, "fitAIC"),
         model = map_dbl(fit, "model"))

Error: Problem with mutate() column fit. i fit = map(...). i fit must be size 6 or 1, not 3.

I understand that not all of the models will fit, I will examine all of the fits relative to other models later.


Solution

  • How about this:

    library(litterfitter)
    library(tidyverse)
    
    decomp_test <- structure(list(site_code = c("CCPp1a", "CCPp1a", "CCPp1a", "CCPp1a", 
                                                "CCPp1a", "CCPp1b", "CCPp1b", "CCPp1b", "CCPp1b", "CCPp1b", "CCPp1c", 
                                                "CCPp1c", "CCPp1c", "CCPp1c", "CCPp1c", "CCPp1d", "CCPp1d", "CCPp1d", 
                                                "CCPp1d", "CCPp1d", "CCPp1e", "CCPp1e", "CCPp1e", "CCPp1e", "CCPp1e", 
                                                "CCPp1f", "CCPp1f", "CCPp1f", "CCPp1f", "CCPp1f"), days_between = c(0L, 
                                                                                                                    118L, 229L, 380L, 572L, 0L, 118L, 229L, 380L, 572L, 0L, 118L, 
                                                                                                                    229L, 380L, 572L, 0L, 118L, 229L, 380L, 572L, 0L, 118L, 229L, 
                                                                                                                    380L, 572L, 0L, 118L, 229L, 380L, 572L), mass_remaining = c(1, 
                                                                                                                                                                                0.7587478816, 0.7366473295, 0.6038150404, 0.6339366063, 1, 0.7609346914, 
                                                                                                                                                                                0.7487194938, 0.7336179508, 0.6595702348, 1, 0.777213425, 0.734006734, 
                                                                                                                                                                                0.6963752241, 0.5827854154, 1, 0.7716566866, 0.7002094345, 0.6913555798, 
                                                                                                                                                                                0.7519095328, 1, 0.7403565314, 0.6751289171, 0.6572164948, 0.620339994, 
                                                                                                                                                                                1, 0.8126440236, 0.7272999401, 0.7223268259, 0.6805293006)), row.names = c(NA, 
                                                                                                                                                                                                                                                           -30L), class = "data.frame")
    
    #Test data-frame with a small number of sites
    
    discrete_paralell <-
      decomp_test %>%
      group_by(site_code) %>% 
      summarise(fit = list(fit_litter(time=days_between ,mass.remaining= mass_remaining,
                                 model='discrete.parallel',iters=1000)$optimFit$par)) %>% 
      unnest_wider(fit) %>% 
      setNames(c("site_code", "par_1", "par_2", "par_3"))
    #> Number of successful fits:  898  out of 1000
    #> Number of successful fits:  912  out of 1000
    #> Warning in fit_litter(time = days_between, mass.remaining = mass_remaining, :
    #> one or more parameters fit on the boundary, check fit closely
    #> Number of successful fits:  866  out of 1000
    #> Number of successful fits:  981  out of 1000
    #> Warning in fit_litter(time = days_between, mass.remaining = mass_remaining, :
    #> one or more parameters fit on the boundary, check fit closely
    #> Number of successful fits:  895  out of 1000
    #> Warning in fit_litter(time = days_between, mass.remaining = mass_remaining, :
    #> one or more parameters fit on the boundary, check fit closely
    #> Number of successful fits:  907  out of 1000
    #> Warning in fit_litter(time = days_between, mass.remaining = mass_remaining, :
    #> one or more parameters fit on the boundary, check fit closely
    #> New names:
    #> • `` -> `...1`
    #> • `` -> `...2`
    #> • `` -> `...3`
    #> New names:
    #> New names:
    #> New names:
    #> New names:
    #> New names:
    #> • `` -> `...1`
    #> • `` -> `...2`
    #> • `` -> `...3`
    
    discrete_paralell
    #> # A tibble: 6 × 4
    #>   site_code par_1    par_2    par_3
    #>   <chr>     <dbl>    <dbl>    <dbl>
    #> 1 CCPp1a    0.819 0.000512 0.596   
    #> 2 CCPp1b    0.738 0.0001   0.0161  
    #> 3 CCPp1c    0.120 0.257    0.000685
    #> 4 CCPp1d    0.256 0.0187   0.0001  
    #> 5 CCPp1e    0.332 0.0119   0.0001  
    #> 6 CCPp1f    0.273 0.00954  0.0001
    

    Created on 2023-01-17 by the reprex package (v2.0.1)