knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  class.warning = "collapsable-warnings",
  warning = FALSE,
  fig.path = "perf-",
  fig.height = 8.5,
  fig.width = 8,
  message = FALSE,
  error   = FALSE
)

suppressPackageStartupMessages({
  library("dplyr")
  library("ggplot2")
})

This vignette presents some performance tests ran between fundiversity and other functional diversity packages. Note that to avoid the dependency on other packages, this vignette is pre-computed.

Other packages to compute FD indices

Main functions

Here is a table that summarizes the comparable functions (and their arguments) for functions included in fundiversity. Note that the package name is indicated before :: followed by the function name.

| Index Type | Index Name | Source | fundiversity function | Equivalent Functions | |:-----------------|:--------------------------------------------------|:------------------------------|:------------------------|----------------------| | α-diversity | Functional Dispersion (FDis) | @Laliberte_distancebased_2010 | fd_fdis() | ~~BAT::dispersion()~~ (doesn't compute FDis)
FD::fdisp()
~~hillR::hill_func()~~ (actually rely on FD for FDis computations and standardize the traits without telling the user)
mFD::alpha.fd.multidim(..., ind_vect = "fdis") | | α-diversity | Functional Divergence (FDiv) | @Villeger_New_2008 | fd_fdiv() | mFD::alpha.fd.multidim(..., ind_vect = "fdiv") | | α-diversity | Functional Evenness (FEve) | @Villeger_New_2008 | fd_feve() | mFD::alpha.fd.multidim(..., ind_vect = "feve") | | α-diversity | Functional Richness (FRic) | @Villeger_New_2008 | fd_fric() | BAT::alpha() (tree, not strictly equal)
BAT::hull.alpha() (hull)
mFD::alpha.fd.multidim(..., ind_vect = "fric") | | α-diversity | Rao's Quadratic Entropy (Q) | @Villeger_Decomposing_2013 | fd_raoq() | adiv::QE()
BAT::rao()
hillR::hill_func() (standardize traits without warning)
mFD::alpha.fd.hill(..., q = 2, tau = "max") (returns a slightly modified version of Q according to @Ricotta_Diversity_2009) | | β-diversity | Functional Richness Intersection (FRic_intersect) | @Rao_Diversity_1982 | fd_fric_intersect() | betapart::functional.beta.pair()
hillR::hill_func_parti_pairwise() |

The other packages are thus: adiv [@Pavoine_adiv_2020], BAT [@Cardoso_BAT_2015], betapart [@Baselga_betapart_2012], FD [@Laliberte_FD_2014], hillR [@Li_hillR_2018], and mFD [@Magneville_mFD_2022]. For fairness of comparison, even if FD::dbFD() contains most indices we're not considering it as it computes all indices together for each call, and would necessarily be slower.

Benchmark between packages

We will now benchmark the functions included in fundiversity with the corresponding function in other packages using the microbenchmark::microbenchmark() function. We will use the fairly small (~220 species, 8 sites, 4 traits) provided dataset in fundiversity.

tictoc::tic()  # Time execution of vignette
library(fundiversity)
data("traits_birds", package = "fundiversity")
data("site_sp_birds", package = "fundiversity")

dist_traits_birds <- dist(traits_birds)

Functional Dispersion (FDis)

fdis_bench <- microbenchmark::microbenchmark(
  fundiversity = {
    fundiversity::fd_fdis(traits_birds, site_sp_birds)
  },
  FD = {
    FD::fdisp(dist_traits_birds, site_sp_birds)
  },
  mFD = {
    mFD::alpha.fd.multidim(
    traits_birds, site_sp_birds, ind_vect = "fdis",
    scaling = FALSE, verbose = FALSE, details_returned = FALSE
  )
  },
  times = 30
)

ggplot2::autoplot(fdis_bench) +
  labs(title = "Functional Dispersion (FDis)")

Functional Divergence (FDiv)

fdiv_bench <- microbenchmark::microbenchmark(
  fundiversity = fd_fdiv(traits_birds, site_sp_birds),
  mFD = mFD::alpha.fd.multidim(
    traits_birds, site_sp_birds, ind_vect = "fdiv",
    scaling = FALSE, verbose = FALSE
  ),
  times = 30
)

ggplot2::autoplot(fdiv_bench) +
  labs(title = "Functional Divergence (FDiv)")

Functional Evenness (FEve)

feve_bench <- microbenchmark::microbenchmark(
  fundiversity = fd_feve(traits_birds, site_sp_birds),
  mFD = mFD::alpha.fd.multidim(
    traits_birds, site_sp_birds, ind_vect = "feve",
    scaling = FALSE, verbose = FALSE
  ),
  times = 30
)

ggplot2::autoplot(feve_bench) +
  labs(title = "Functional Evenness (FEve)")

Functional Richness (FRic)

fric_bench <- microbenchmark::microbenchmark(
  fundiversity = fd_fric(traits_birds, site_sp_birds),
  BAT_tree = BAT::alpha(
    site_sp_birds, traits_birds
  ),
  BAT_alpha_hull = BAT::hull.alpha(
    BAT::hull.build(site_sp_birds, traits_birds)
  ),
  mFD = mFD::alpha.fd.multidim(
    traits_birds, site_sp_birds, ind_vect = "fric",
    scaling = FALSE, verbose = FALSE
  ),
  times = 30
)

ggplot2::autoplot(fric_bench) +
  labs(title = "Functional Richness (FRic)")

Functional Richness Intersection (FRic_intersect)

fric_bench <- microbenchmark::microbenchmark(
  fundiversity  = fd_fric_intersect(traits_birds, site_sp_birds) ,
  betapart = betapart::functional.beta.pair(
    site_sp_birds, traits_birds
  ),
  hillR = hillR::hill_func_parti_pairwise(
    site_sp_birds, traits_birds, .progress = FALSE
  ),
  times = 30
)

ggplot2::autoplot(fric_bench) +
  labs(title = "Functional Richness Intersection (FRic)")

Rao's Quadratic Entropy (Q)

raoq_bench <- fric_bench <- microbenchmark::microbenchmark(
  fundiversity = fd_raoq(traits_birds, site_sp_birds),
  adiv= adiv::QE(
    site_sp_birds, dist_traits_birds
  ),
  BAT_rao           = BAT::rao(
    site_sp_birds, distance = traits_birds
  ),
  hillR_hill_func   = hillR::hill_func(
    site_sp_birds, traits_birds, fdis = FALSE
  ),
  mFD_alpha_fd_hill = mFD::alpha.fd.hill(
    site_sp_birds, dist_traits_birds, q = 2,
    tau = "max"
  ),
  times = 30
)

ggplot2::autoplot(raoq_bench) +
  labs(title = "Rao's Quadatric Entropy (Q)")

Benchmark within fundiversity

We now proceed to the performance evaluation of functions within fundiversity with datasets of increasing sizes.

Increasing the number of species

make_more_sp <- function(n) {
  traits <- do.call(rbind, replicate(n, traits_birds, simplify = FALSE))
  row.names(traits) <- paste0("sp", seq_len(nrow(traits)))

  site_sp <- do.call(cbind, replicate(n, site_sp_birds, simplify = FALSE))
  colnames(site_sp) <- paste0("sp", seq_len(ncol(site_sp)))

  list(tr = traits, si = site_sp)
}

null_sp_1000   <- make_more_sp(5)
null_sp_10000  <- make_more_sp(50)
null_sp_100000 <- make_more_sp(500)

Functional Richness

bench_sp_fric <- microbenchmark::microbenchmark(
  species_200    = fd_fric(     traits_birds, site_sp_birds),
  species_1000   = fd_fric(  null_sp_1000$tr, null_sp_1000$si),
  species_10000  = fd_fric( null_sp_10000$tr, null_sp_10000$si),
  species_100000 = fd_fric(null_sp_100000$tr, null_sp_100000$si),
  times = 30
)

ggplot2::autoplot(bench_sp_fric)
bench_sp_fric

Functional Divergence

bench_sp_fdiv <- microbenchmark::microbenchmark(
  species_200    = fd_fdiv(     traits_birds, site_sp_birds),
  species_1000   = fd_fdiv(  null_sp_1000$tr, null_sp_1000$si),
  species_10000  = fd_fdiv( null_sp_10000$tr, null_sp_10000$si),
  species_100000 = fd_fdiv(null_sp_100000$tr, null_sp_100000$si),
  times = 30
)

ggplot2::autoplot(bench_sp_fdiv)
bench_sp_fdiv

Rao's Quadratic Entropy

bench_sp_raoq <- microbenchmark::microbenchmark(
  species_200    = fd_raoq(     traits_birds, site_sp_birds),
  species_1000   = fd_raoq(  null_sp_1000$tr, null_sp_1000$si),
  species_10000  = fd_raoq( null_sp_10000$tr, null_sp_10000$si),
  times = 30
)

ggplot2::autoplot(bench_sp_raoq)
bench_sp_raoq

Functional Evenness

bench_sp_feve <- microbenchmark::microbenchmark(
  species_200    = fd_feve(     traits_birds, site_sp_birds),
  species_1000   = fd_feve(  null_sp_1000$tr, null_sp_1000$si),
  species_10000  = fd_feve( null_sp_10000$tr, null_sp_10000$si),
  times = 15
)

ggplot2::autoplot(bench_sp_feve)
bench_sp_feve

Comparing between indices

all_bench_sp <- list(fric = bench_sp_fric,
                     fdiv = bench_sp_fdiv,
                     raoq = bench_sp_raoq,
                     feve = bench_sp_feve) %>%
  bind_rows(.id = "fd_index") %>%
  mutate(n_sp = gsub("species_", "", expr) %>%
           as.numeric())

all_bench_sp %>%
  ggplot(aes(n_sp, time * 1e-9, color = fd_index)) +
  geom_point(alpha = 1/3) +
  geom_smooth() +
  scale_x_log10() +
  scale_y_log10() +
  scale_color_brewer(type = "qual",
                     labels = c(fric = "FRic", fdiv = "FDiv", raoq = "Rao's Q",
                                feve = "FEve")) +
  labs(title = "Performance comparison between indices",
       x = "# of species", y = "Time (in seconds)",
       color = "FD index") +
  theme_bw() +
  theme(aspect.ratio = 1)

Increasing the number of sites

make_more_sites <- function(n) {
  site_sp <- do.call(rbind, replicate(n, site_sp_birds, simplify = FALSE))
  rownames(site_sp) <- paste0("s", seq_len(nrow(site_sp)))

  site_sp
}

site_sp_100   <- make_more_sites(12)
site_sp_1000  <- make_more_sites(120)
site_sp_10000 <- make_more_sites(1200)

Functional Richness

bench_sites_fric <- microbenchmark::microbenchmark(
  sites_10    = fd_fric(traits_birds, site_sp_birds),
  sites_100   = fd_fric(traits_birds, site_sp_100),
  sites_1000  = fd_fric(traits_birds, site_sp_1000),
  sites_10000 = fd_fric(traits_birds, site_sp_10000),
  times = 15
)

ggplot2::autoplot(bench_sites_fric)
bench_sites_fric

Functional Divergence

bench_sites_fdiv <- microbenchmark::microbenchmark(
  sites_10    = fd_fdiv(traits_birds, site_sp_birds),
  sites_100   = fd_fdiv(traits_birds, site_sp_100),
  sites_1000  = fd_fdiv(traits_birds, site_sp_1000),
  sites_10000 = fd_fdiv(traits_birds, site_sp_10000),
  times = 15
)

ggplot2::autoplot(bench_sites_fdiv)
bench_sites_fdiv

Rao's Quadratic Entropy

bench_sites_raoq = microbenchmark::microbenchmark(
  sites_10    = fd_raoq(traits = NULL, site_sp_birds, dist_traits_birds),
  sites_100   = fd_raoq(traits = NULL, site_sp_100,   dist_traits_birds),
  sites_1000  = fd_raoq(traits = NULL, site_sp_1000,  dist_traits_birds),
  sites_10000 = fd_raoq(traits = NULL, site_sp_10000, dist_traits_birds),
  times = 15
)

ggplot2::autoplot(bench_sites_raoq)
bench_sites_raoq

Functional Evenness

bench_sites_feve <- microbenchmark::microbenchmark(
  sites_10    = fd_feve(traits = NULL, site_sp_birds, dist_traits_birds),
  sites_100   = fd_feve(traits = NULL, site_sp_100,   dist_traits_birds),
  sites_1000  = fd_feve(traits = NULL, site_sp_1000,  dist_traits_birds),
  sites_10000 = fd_feve(traits = NULL, site_sp_10000, dist_traits_birds),
  times = 15
)

ggplot2::autoplot(bench_sites_feve)
bench_sites_feve

Comparing between indices

all_bench_sites <- list(fric = bench_sites_fric,
                        fdiv = bench_sites_fdiv,
                        raoq = bench_sites_raoq,
                        feve = bench_sites_feve) %>%
  bind_rows(.id = "fd_index") %>%
  mutate(n_sites = gsub("sites", "", expr) %>%
           as.numeric())

all_bench_sites %>%
  ggplot(aes(n_sites, time * 1e-9, color = fd_index)) +
  geom_point(alpha = 1/3) +
  geom_smooth() +
  scale_x_log10() +
  scale_y_log10() +
  scale_color_brewer(type = "qual",
                     labels = c(fric = "FRic", fdiv = "FDiv", raoq = "Rao's Q",
                                feve = "FEve")) +
  labs(title = "Performance comparison between indices",
       x = "# of sites", y = "Time (in seconds)",
       color = "FD index") +
  theme_bw() +
  theme(aspect.ratio = 1)

Session info of the machine on which the benchmark was ran and time it took to run

tictoc::toc(
  func.toc = function(x, y, msg) tictoc::toc.outmsg(
    x, y, paste0(msg, " seconds needed to generate this document")
    )
)
sessioninfo::session_info()

References

{js, echo=FALSE} (function() { var codes = document.querySelectorAll('.collapsable-warnings'); var code, i, d, s, p; for (i = 0; i < codes.length; i++) { code = codes[i]; p = code.parentNode; d = document.createElement('details'); s = document.createElement('summary'); s.innerText = 'Warnings'; // <details><summary>Details</summary></details> d.appendChild(s); // move the code into <details> p.replaceChild(d, code); d.appendChild(code); } })();



Bisaloo/fundiversity documentation built on April 4, 2024, 12:24 a.m.