EvolEcolGroup / tidysdm

R package to fit species distribution models (SDMs) using the 'tidymodels' framework
https://evolecolgroup.github.io/tidysdm/
GNU Affero General Public License v3.0
23 stars 6 forks source link

No `collect_metric()` exists for this type of object. #29

Closed ramiromagno closed 8 months ago

ramiromagno commented 8 months ago

Hello,

Thank you for developing this amazing package!

I am trying to run your example code provided in your tidysdm overview vignette but I am getting an issue when I call the collect_metric() on the lacerta_ensemble object. Could you please take a look?

Reprex

library(tidysdm)
#> Loading required package: tidymodels
#> Loading required package: spatialsample
library(sf)
#> Linking to GEOS 3.12.0, GDAL 3.7.1, PROJ 9.2.1; sf_use_s2() is TRUE
library(pastclim)
#> Loading required package: terra
#> terra 1.7.55
#> 
#> Attaching package: 'terra'
#> The following object is masked from 'package:tidyr':
#> 
#>     extract
#> The following object is masked from 'package:scales':
#> 
#>     rescale
#> 
#> Attaching package: 'pastclim'
#> The following objects are masked from 'package:tidysdm':
#> 
#>     date2ybp, ybp2date
library(tidyterra)
#> 
#> Attaching package: 'tidyterra'
#> The following object is masked from 'package:stats':
#> 
#>     filter
library(ggplot2)

data(lacerta)
lacerta
#> # A tibble: 1,297 × 3
#>           ID latitude longitude
#>        <dbl>    <dbl>     <dbl>
#>  1 858029749     42.6     -7.09
#>  2 858029738     42.6     -7.09
#>  3 614631090     41.4     -7.90
#>  4 614631085     41.3     -7.81
#>  5 614631083     41.3     -7.81
#>  6 614631080     41.4     -7.83
#>  7 614631072     41.4     -7.81
#>  8 614559731     40.3     -7.70
#>  9 614559728     40.4     -7.70
#> 10 614559657     40.4     -7.56
#> # ℹ 1,287 more rows

lacerta <- st_as_sf(lacerta, coords = c("longitude", "latitude"))
st_crs(lacerta) <- 4326

# Iberia peninsula extension
iberia_poly <- terra::vect("POLYGON((-9.8 43.3,-7.8 44.1,-2.0 43.7,3.6 42.5,3.8 41.5,1.3 40.8,0.3 39.5,0.9 38.6,-0.4 37.5,-1.6 36.7,-2.3 36.3,-4.1 36.4,-4.5 36.4,-5.0 36.1,-5.6 36.0,-6.3 36.0,-7.1 36.9,-9.5 36.6,-9.4 38.0,-10.6 38.9,-9.5 40.8,-9.8 43.3))")

crs(iberia_poly) <- "lonlat"
gdal(warn = 3)
land_mask <- rast(system.file("extdata/lacerta_land_mask.nc",
                              package = "tidysdm"))

ggplot() +
  geom_spatraster(data = land_mask, aes(fill = land_mask_1985)) +
  geom_sf(data = lacerta)


# Thinning step

set.seed(1234567)
lacerta <- thin_by_cell(lacerta, raster = land_mask)
nrow(lacerta)
#> [1] 231

ggplot() +
  geom_spatraster(data = land_mask, aes(fill = land_mask_1985)) +
  geom_sf(data = lacerta)


set.seed(1234567)
lacerta_thin <- thin_by_dist(lacerta, dist_min = km2m(20))
nrow(lacerta_thin)
#> [1] 113

ggplot() +
  geom_spatraster(data = land_mask, aes(fill = land_mask_1985)) +
  geom_sf(data = lacerta_thin)


set.seed(1234567)
lacerta_thin <- sample_pseudoabs(lacerta_thin,
                                 n = 3 * nrow(lacerta_thin),
                                 raster = land_mask,
                                 method = c("dist_min", km2m(50))
)

ggplot() +
  geom_spatraster(data = land_mask, aes(fill = land_mask_1985)) +
  geom_sf(data = lacerta_thin, aes(col = class))


gdal(warn = 3)
climate_present <-
  rast(system.file("extdata/lacerta_climate_present_10m.nc",
                   package = "tidysdm"))
climate_vars <- names(climate_present)

lacerta_thin <- lacerta_thin %>%
  bind_cols(terra::extract(climate_present, lacerta_thin, ID = FALSE))

lacerta_thin %>% plot_pres_vs_bg(class)

lacerta_thin %>% dist_pres_vs_bg(class)
#>     bio19     bio12     bio16     bio02     bio13     bio07     bio05     bio04 
#> 0.6935026 0.6929654 0.6885097 0.6776561 0.6679894 0.6542063 0.6243068 0.6071527 
#>     bio09     bio10     bio17     bio15     bio18     bio06     bio08     bio14 
#> 0.5506741 0.4855064 0.4318872 0.4241999 0.3600587 0.3454245 0.3108560 0.2954351 
#>     bio11     bio03     bio01  altitude 
#> 0.2317079 0.2173934 0.2045136 0.1554400

vars_to_keep <- lacerta_thin %>% dist_pres_vs_bg(class)
vars_to_keep <- names(vars_to_keep[vars_to_keep > 0.30])
lacerta_thin <- lacerta_thin %>% select(all_of(c(vars_to_keep, "class")))
vars_to_keep
#>  [1] "bio19" "bio12" "bio16" "bio02" "bio13" "bio07" "bio05" "bio04" "bio09"
#> [10] "bio10" "bio17" "bio15" "bio18" "bio06" "bio08"

suggested_vars <- c("bio05", "bio06", "bio13", "bio14", "bio15")
pairs(climate_present[[suggested_vars]])


climate_present <- climate_present[[suggested_vars]]
vars_uncor <- filter_high_cor(climate_present, cutoff = 0.7)
vars_uncor
#> [1] "bio15" "bio05" "bio13" "bio06"
#> attr(,"to_remove")
#> [1] "bio14"

lacerta_thin <- lacerta_thin %>% select(all_of(c(vars_uncor, "class")))
climate_present <- climate_present[[vars_uncor]]

lacerta_rec <- recipe(lacerta_thin, formula = class ~ .)
lacerta_rec
#> 
#> ── Recipe ──────────────────────────────────────────────────────────────────────
#> 
#> ── Inputs
#> Number of variables by role
#> outcome:   1
#> predictor: 4
#> coords:    2

lacerta_thin %>% check_sdm_presence(class)
#> [1] TRUE

lacerta_models <-
  # create the workflow_set
  workflow_set(
    preproc = list(default = lacerta_rec),
    models = list(
      # the standard glm specs
      glm = sdm_spec_glm(),
      # rf specs with tuning
      rf = sdm_spec_rf(),
      # boosted tree model (gbm) specs with tuning
      gbm = sdm_spec_boost_tree(),
      # maxent specs with tuning
      maxent = sdm_spec_maxent()
    ),
    # make all combinations of preproc and models,
    cross = TRUE
  ) %>%
  # tweak controls to store information needed later to create the ensemble
  option_add(control = control_ensemble_grid())

set.seed(100)
lacerta_cv <- spatial_block_cv(lacerta_thin, v = 5)
autoplot(lacerta_cv)


set.seed(1234567)
lacerta_models <-
  lacerta_models %>%
  workflow_map("tune_grid",
               resamples = lacerta_cv, grid = 3,
               metrics = sdm_metric_set(), verbose = TRUE
  )
#> i    No tuning parameters. `fit_resamples()` will be attempted
#> i 1 of 4 resampling: default_glm
#> ✔ 1 of 4 resampling: default_glm (188ms)
#> i 2 of 4 tuning:     default_rf
#> i Creating pre-processing data to finalize unknown parameter: mtry
#> ✔ 2 of 4 tuning:     default_rf (763ms)
#> i 3 of 4 tuning:     default_gbm
#> i Creating pre-processing data to finalize unknown parameter: mtry
#> ✔ 3 of 4 tuning:     default_gbm (4s)
#> i 4 of 4 tuning:     default_maxent
#> ✔ 4 of 4 tuning:     default_maxent (1.4s)

autoplot(lacerta_models)


lacerta_ensemble <- simple_ensemble() %>%
  add_member(lacerta_models, metric = "boyce_cont")
lacerta_ensemble
#> A simple_ensemble of models
#> 
#> Members:
#> • default_glm
#> • default_rf
#> • default_gbm
#> • default_maxent
#> 
#> Available metrics:
#> • boyce_cont
#> • roc_auc
#> • tss_max
#> 
#> Metric used to tune workflows:
#> • boyce_cont

autoplot(lacerta_ensemble)


lacerta_ensemble %>% collect_metrics()
#> Error in `collect_metrics()`:
#> ! No `collect_metric()` exists for this type of object.
#> Backtrace:
#>     ▆
#>  1. ├─lacerta_ensemble %>% collect_metrics()
#>  2. ├─tune::collect_metrics(.)
#>  3. └─tune:::collect_metrics.default(.)
#>  4.   └─rlang::abort("No `collect_metric()` exists for this type of object.")

Session info

R version 4.3.1 (2023-06-16)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Arch Linux

Matrix products: default
BLAS:   /usr/lib/libblas.so.3.11.0 
LAPACK: /usr/lib/liblapack.so.3.11.0

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8    LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

time zone: Europe/Lisbon
tzcode source: system (glibc)

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] maxnet_0.1.4        xgboost_1.7.6.1     ranger_0.16.0       tidyterra_0.4.0     pastclim_2.0.0      terra_1.7-55       
 [7] sf_1.0-14           tidysdm_0.9.1       spatialsample_0.4.0 yardstick_1.2.0     workflowsets_1.0.1  workflows_1.1.3    
[13] tune_1.1.2          tidyr_1.3.0         tibble_3.2.1        rsample_1.2.0       recipes_1.0.8       purrr_1.0.2        
[19] parsnip_1.1.1       modeldata_1.2.0     infer_1.0.5         ggplot2_3.4.4       dplyr_1.1.3         dials_1.2.0        
[25] scales_1.2.1        broom_1.0.5         tidymodels_1.1.1   

loaded via a namespace (and not attached):
 [1] DBI_1.1.3           s2_1.1.4            testthat_3.2.0      rlang_1.1.1         magrittr_2.0.3      furrr_0.3.1        
 [7] e1071_1.7-13        compiler_4.3.1      vctrs_0.6.4         lhs_1.1.6           shape_1.4.6         pkgconfig_2.0.3    
[13] wk_0.8.0            backports_1.4.1     ellipsis_0.3.2      labeling_0.4.3      utf8_1.2.3          prodlim_2023.08.28 
[19] glmnet_4.1-8        reprex_2.0.2        overlapping_2.1     jsonlite_1.8.7      parallel_4.3.1      prettyunits_1.2.0  
[25] R6_2.5.1            parallelly_1.36.0   rpart_4.1.19        brio_1.1.3          lubridate_1.9.3     Rcpp_1.0.11        
[31] iterators_1.0.14    future.apply_1.11.0 Matrix_1.6-1.1      splines_4.3.1       nnet_7.3-19         timechange_0.2.0   
[37] tidyselect_1.2.0    rstudioapi_0.15.0   timeDate_4022.108   codetools_0.2-19    listenv_0.9.0       lattice_0.21-8     
[43] withr_2.5.1         future_1.33.0       survival_3.5-7      units_0.8-4         proxy_0.4-27        pillar_1.9.0       
[49] KernSmooth_2.23-22  foreach_1.5.2       generics_0.1.3      rprojroot_2.0.3     munsell_0.5.0       globals_0.16.2     
[55] class_7.3-22        glue_1.6.2          tools_4.3.1         data.table_1.14.8   gower_1.0.1         fs_1.6.3           
[61] grid_4.3.1          DALEX_2.4.3         ipred_0.9-14        colorspace_2.1-0    patchwork_1.1.3     cli_3.6.1          
[67] DiceDesign_1.9      fansi_1.0.5         lava_1.7.2.1        gtable_0.3.4        GPfit_1.0-8         digest_0.6.33      
[73] classInt_0.4-10     farver_2.1.1        lifecycle_1.0.3     hardhat_1.3.0       here_1.0.1          MASS_7.3-60
dramanica commented 8 months ago

You have an old version of tidysdm (0.9.1). The method you want is in 0.9.3, which is on CRAN, so updating your packages should do the trick.

dramanica commented 8 months ago

@ramiromagno I'll close the issue, but let me know if updating the package does not work and we can reopen it.

ramiromagno commented 8 months ago

Thank you! I will try that! If you don't hear from me, it's because installing the package did indeed solve it.