Skip to contents

Introduction

State of the Field

This analysis provides a comparative benchmark of R packages designed for calculating standard and phylogenetic metrics of alpha and beta diversity. The primary objective is to evaluate their computational efficiency, with a focus on processing speed and memory allocation. Packages that rely on these foundational libraries as dependencies have been omitted from this study to isolate the performance of the core implementations.

R Package Classic alpha/beta Phylogenetic alpha/beta
abdiv Serial R none
adiv Serial R Serial R
ampvis2 vegan Serial R
ecodist Serial C/R none
ecodive Parallel C Parallel C
entropart Serial R none
GUniFrac none Serial C
labdsv Serial FORTRAN none
parallelDist Parallel C++ none
philentropy Serial C++ none
phyloregion vegan Serial R
phyloseq vegan Parallel R
picante vegan Serial R
tabula Serial R none
vegan Serial C none

Methodology

The bench R package was employed to quantify the computational runtime and memory allocation for the diversity algorithms within each of the 15 selected packages. All benchmarks were executed on a host system with the following hardware and software configuration:

CPU: 6-Core Intel i5-9600K @ 3.70GHz
RAM: 64.0 GB
OS: Windows 11 Pro (64-bit, Version 25H2, Build 26200.7171)

Furthermore, the bench::mark() function was utilized to verify that the outputs from all benchmarked expressions were numerically equivalent, ensuring the consistency and comparability of the results.


Setup

Two standard datasets from the rbiom R package, hmp50 and gems, were selected for this evaluation. The hmp50 dataset, which includes 50 samples and an associated phylogenetic tree, was used to benchmark the computationally intensive phylogenetic metrics, such as UniFrac and Faith’s PD. For the traditional diversity metrics, which are significantly less demanding, the larger gems dataset, comprising 1,006 samples, was employed.

To account for the heterogeneous input and output formats across the 15 R packages, necessary data transformations were performed. To ensure that the benchmarks exclusively measured the performance of the diversity calculations, these data conversion steps were executed outside of the timed code blocks whenever possible.

Click to reveal R code.
install.packages('pak')

# Tools and Datasets for Benchmarking Report
pak::pkg_install(pkg = c(
  'bench', 'dplyr', 'ggplot2', 'ggrepel', 'rbiom', 'svglite' ))

# Diversity Metric Implementations
pak::pkg_install(pkg = c(
  'abdiv', 'adiv', 'ecodist', 'ecodive', 'entropart', 'GUniFrac', 
  'kasperskytte/ampvis2', 'labdsv', 'parallelDist', 'philentropy', 
  'phyloregion', 'phyloseq', 'picante', 'tabula', 'vegan' ))


# Software Versions

version$version.string
#> [1] "R version 4.5.2 (2025-10-31 ucrt)"

data.frame(ver = sapply(FUN = packageDescription, fields = 'Version', c(
  'bench', 'dplyr', 'ggplot2', 'ggrepel', 'rbiom',
  'abdiv', 'adiv', 'ecodist', 'ecodive', 'entropart', 'GUniFrac', 
  'ampvis2', 'labdsv', 'parallelDist', 'philentropy', 
  'phyloregion', 'phyloseq', 'picante', 'tabula', 'vegan' )))
#>                 ver
#> bench         1.1.4
#> dplyr         1.1.4
#> ggplot2       4.0.1
#> ggrepel       0.9.6
#> rbiom         2.2.1
#> abdiv         0.2.0
#> adiv          2.2.1
#> ecodist       2.1.3
#> ecodive       2.2.0
#> entropart    1.6-16
#> GUniFrac        1.9
#> ampvis2      2.8.11
#> labdsv        2.1-2
#> parallelDist  0.2.7
#> philentropy  0.10.0
#> phyloregion   1.0.9
#> phyloseq     1.54.0
#> picante       1.8.2
#> tabula        3.3.2
#> vegan         2.7-2

library(bench)
library(ggplot2)
library(ggrepel)
library(dplyr)
library(Matrix)

(n_cpus <- ecodive::n_cpus())
#> [1] 6

# abdiv only accepts two samples at a time
pairwise <- function (f, data, ...) {
  pairs <- utils::combn(nrow(data), 2)
  structure(
    mapply(
      FUN = function (i, j) f(data[i,], data[j,], ...), 
      i   = pairs[1,], j = pairs[2,] ),
    class  = 'dist',
    Labels = rownames(data),
    Size   = nrow(data),
    Diag   = FALSE,
    Upper  = FALSE )
}


# Remove any extraneous attributes from dist objects,
# allowing them to be compared with `all.equal()`.
cleanup <- function (x) {
  for (i in setdiff(names(attributes(x)), c('class', 'Labels', 'Size', 'Diag', 'Upper')))
    attr(x, i) <- NULL
  return (x)
}


# HMP50 dataset has 50 samples; convert to relative abundances
hmp50       <- rbiom::hmp50
hmp50_phy   <- rbiom::convert_to_phyloseq(hmp50)
hmp50_mtx   <- t(apply(as.matrix(hmp50), 2L, function (x) x / sum(x)))
hmp50_mtx_t <- t(hmp50_mtx)
hmp50_dgC   <- as(hmp50_mtx, 'dgCMatrix')
hmp50_dgC_t <- t(hmp50_dgC)
hmp50_tree  <- hmp50$tree


# GEMS dataset has 1006 samples; convert to relative abundances
gems_mtx   <- t(apply(as.matrix(rbiom::gems), 2L, function (x) x / sum(x)))
gems_dgC   <- as(gems_mtx, 'dgCMatrix')
gems_dgC_t <- t(gems_dgC)

## Bray-Curtis Dissimilarity
bray_curtis_res <- bench::mark(
  iterations = 10,
  'abdiv'        = cleanup(pairwise(abdiv::bray_curtis, gems_mtx)),
  'ecodist'      = cleanup(ecodist::bcdist(gems_mtx)),
  'ecodive'      = cleanup(ecodive::bray(gems_dgC_t, norm = 'none', margin = 2)),
  'labdsv'       = cleanup(labdsv::dsvdis(gems_mtx, 'bray/curtis')),
  'parallelDist' = cleanup(parallelDist::parallelDist(gems_mtx, 'bray')),
  'philentropy'  = cleanup(philentropy::distance(gems_mtx, 'sorensen', test.na = FALSE, use.row.names = TRUE, as.dist.obj = TRUE, mute.message = TRUE)),
  'tabula'       = cleanup(1 - pairwise(tabula::index_bray, gems_mtx)),
  'vegan'        = cleanup(vegan::vegdist(gems_mtx, 'bray')) )


## Jaccard Distance
jaccard_res <- bench::mark(
  iterations = 10,
  'abdiv'        = cleanup(pairwise(abdiv::jaccard, gems_mtx)),
  'ecodist'      = cleanup(ecodist::distance(gems_mtx, 'jaccard')),
  'ecodive'      = cleanup(ecodive::jaccard(gems_dgC_t, margin = 2)),
  'parallelDist' = cleanup(parallelDist::parallelDist(gems_mtx, 'binary')),
  'philentropy'  = cleanup(philentropy::distance(gems_mtx > 0, 'jaccard', test.na = FALSE, use.row.names = TRUE, as.dist.obj = TRUE, mute.message = TRUE)),
  'phyloregion'  = cleanup(phyloregion::beta_diss(gems_mtx, 'jaccard')$beta.jac),
  'stats'        = cleanup(stats::dist(gems_mtx, 'binary')),
  'vegan'        = cleanup(vegan::vegdist(gems_mtx, 'jaccard', binary = TRUE)) )


## Manhattan Distance
manhattan_res <- bench::mark(
  iterations = 10,
  'abdiv'        = cleanup(pairwise(abdiv::manhattan, gems_mtx)),
  'ecodist'      = cleanup(ecodist::distance(gems_mtx, 'manhattan')),
  'ecodive'      = cleanup(ecodive::manhattan(gems_dgC_t, norm = 'none', margin = 2)),
  'parallelDist' = cleanup(parallelDist::parallelDist(gems_mtx, 'manhattan')),
  'philentropy'  = cleanup(philentropy::distance(gems_mtx, 'manhattan', test.na = FALSE, use.row.names = TRUE, as.dist.obj = TRUE, mute.message = TRUE)),
  'stats'        = cleanup(stats::dist(gems_mtx, 'manhattan')),
  'vegan'        = cleanup(vegan::vegdist(gems_mtx, 'manhattan')) )


## Euclidean Distance
euclidean_res <- bench::mark(
  iterations = 10,
  'abdiv'        = cleanup(pairwise(abdiv::euclidean, gems_mtx)),
  'ecodist'      = cleanup(ecodist::distance(gems_mtx, 'euclidean')),
  'ecodive'      = cleanup(ecodive::euclidean(gems_dgC_t, norm = 'none', margin = 2)),
  'parallelDist' = cleanup(parallelDist::parallelDist(gems_mtx, 'euclidean')),
  'philentropy'  = cleanup(philentropy::distance(gems_mtx, 'euclidean', test.na = FALSE, use.row.names = TRUE, as.dist.obj = TRUE, mute.message = TRUE)),
  'stats'        = cleanup(stats::dist(gems_mtx, 'euclidean')),
  'vegan'        = cleanup(vegan::vegdist(gems_mtx, 'euclidean')) )


## Shannon Diversity Index
shannon_res <- bench::mark(
  iterations  = 10,
  'abdiv'       = apply(gems_mtx, 1L, abdiv::shannon),
  'adiv'        = adiv::speciesdiv(gems_mtx, 'Shannon')[,1],
  'ecodive'     = ecodive::shannon(gems_dgC_t, margin = 2),
  'entropart'   = apply(gems_mtx, 1L, entropart::Shannon, CheckArguments = FALSE),
  'philentropy' = apply(gems_mtx, 1L, philentropy::H, unit = 'log'),
  'tabula'      = apply(gems_mtx, 1L, tabula::index_shannon),
  'vegan'       = vegan::diversity(gems_mtx, 'shannon') )


## Gini-Simpson Index
simpson_res <- bench::mark(
  iterations  = 10,
  'abdiv'     = apply(gems_mtx, 1L, abdiv::simpson),
  'adiv'      = adiv::speciesdiv(gems_mtx, 'GiniSimpson')[,1],
  'ecodive'   = ecodive::simpson(gems_dgC_t, margin = 2),
  'entropart' = apply(gems_mtx, 1L, entropart::Simpson, CheckArguments = FALSE),
  'tabula'    = 1 - apply(gems_mtx, 1L, tabula::index_simpson),
  'vegan'     = vegan::diversity(gems_mtx, 'simpson') )


## Faith's Phylogenetic Diversity
faith_res <- bench::mark(
  iterations    = 10,
  check         = FALSE, # entropart has incorrect output on non-ultrametric tree
  'abdiv'       = apply(hmp50_mtx, 1L, abdiv::faith_pd, hmp50_tree),
  'adiv'        = apply(hmp50_mtx, 1L, \(x) adiv::EH(hmp50_tree, colnames(hmp50_mtx)[x > 0])),
  'ecodive'     = ecodive::faith(hmp50_dgC_t, hmp50_tree, margin = 2),
  'entropart'   = apply(hmp50_mtx, 1L, entropart::PDFD, hmp50_tree, CheckArguments = FALSE),
  'phyloregion' = phyloregion::PD(hmp50_mtx, hmp50_tree),
  'picante'     = as.matrix(picante::pd(hmp50_mtx, hmp50_tree))[,'PD'] )


## Unweighted UniFrac
u_unifrac_res <- rbind(
  
  local({
    # cluster for phyloseq
    cl <- parallel::makeCluster(n_cpus)
    doParallel::registerDoParallel(cl)
    on.exit(parallel::stopCluster(cl))
    
    bench::mark(
      iterations    = 10,
      'abdiv'       = cleanup(pairwise(abdiv::unweighted_unifrac, hmp50_mtx, hmp50_tree)),
      'ecodive'     = cleanup(ecodive::unweighted_unifrac(hmp50_dgC_t, hmp50_tree, margin = 2)),
      'GUniFrac'    = cleanup(as.dist(GUniFrac::GUniFrac(hmp50_mtx, hmp50_tree, alpha=1, verbose=FALSE)[[1]][,,2])),
      'phyloregion' = cleanup(phyloregion::unifrac(hmp50_dgC, hmp50_tree)),
      'phyloseq'    = cleanup(phyloseq::UniFrac(hmp50_phy, weighted=FALSE, normalized=FALSE, parallel=TRUE)),
      'picante'     = cleanup(picante::unifrac(hmp50_mtx, hmp50_tree)) )
  }),
  
  # ampvis2 conflicts with phyloseq cluster, so run separately
  local({
    bench::mark(
      iterations = 10,
      'ampvis2'  = {
        cleanup(ampvis2:::dist.unifrac(hmp50_mtx_t, hmp50_tree, weighted=FALSE, normalise=FALSE, num_threads=n_cpus))
        doParallel::stopImplicitCluster() } )
  })
)


## Weighted UniFrac
w_unifrac_res <- rbind(
  
  local({
    # cluster for phyloseq
    cl <- parallel::makeCluster(n_cpus)
    doParallel::registerDoParallel(cl)
    on.exit(parallel::stopCluster(cl))
    
    bench::mark(
      iterations = 10,
      'abdiv'    = cleanup(pairwise(abdiv::weighted_unifrac, hmp50_mtx, hmp50_tree)),
      'ecodive'  = cleanup(ecodive::weighted_unifrac(hmp50_dgC_t, hmp50_tree, margin = 2)),
      'phyloseq' = cleanup(phyloseq::UniFrac(hmp50_phy, weighted=TRUE, normalized=FALSE, parallel=TRUE)) )
  }),
  
  # ampvis2 conflicts with phyloseq cluster, so run separately
  local({
    bench::mark(
      iterations = 10,
      'ampvis2'  = {
        cleanup(ampvis2:::dist.unifrac(hmp50_mtx_t, hmp50_tree, weighted=TRUE, normalise=FALSE, num_threads=n_cpus))
        doParallel::stopImplicitCluster() } )
  })
)


## Weighted Normalized UniFrac
wn_unifrac_res <- rbind(
  
  local({
    # cluster for phyloseq
    cl <- parallel::makeCluster(n_cpus)
    doParallel::registerDoParallel(cl)
    on.exit(parallel::stopCluster(cl))
    
    bench::mark(
      iterations = 10,
      'abdiv'    = cleanup(pairwise(abdiv::weighted_normalized_unifrac, hmp50_mtx, hmp50_tree)),
      'ecodive'  = cleanup(ecodive::normalized_unifrac(hmp50_dgC_t, hmp50_tree, margin = 2)),
      'GUniFrac' = cleanup(as.dist(GUniFrac::GUniFrac(hmp50_mtx, hmp50_tree, alpha=1, verbose=FALSE)[[1]][,,1])),
      'phyloseq' = cleanup(phyloseq::UniFrac(hmp50_phy, weighted=TRUE, normalized=TRUE, parallel=TRUE)) )
  }),
  
  # ampvis2 conflicts with phyloseq cluster, so run separately
  local({
    bench::mark(
      iterations = 10,
      'ampvis2'  = {
        cleanup(ampvis2:::dist.unifrac(hmp50_mtx_t, hmp50_tree, weighted=TRUE, normalise=TRUE, num_threads=n_cpus))
        doParallel::stopImplicitCluster() } )
  })
)


## Weighted Normalized UniFrac
g_unifrac_res <- rbind(
  
  local({
    # cluster for phyloseq
    cl <- parallel::makeCluster(n_cpus)
    doParallel::registerDoParallel(cl)
    on.exit(parallel::stopCluster(cl))
    
    bench::mark(
      iterations = 10,
      'abdiv'    = cleanup(pairwise(abdiv::generalized_unifrac, hmp50_mtx, hmp50_tree, alpha=0.5)),
      'ecodive'  = cleanup(ecodive::generalized_unifrac(hmp50_dgC_t, hmp50_tree, margin=2, alpha=0.5)),
      'GUniFrac' = cleanup(as.dist(GUniFrac::GUniFrac(hmp50_mtx, hmp50_tree, alpha=0.5, verbose=FALSE)[[1]][,,1])) )
  })
)


## Variance Adjusted UniFrac
va_unifrac_res <- rbind(
  
  local({
    # cluster for phyloseq
    cl <- parallel::makeCluster(n_cpus)
    doParallel::registerDoParallel(cl)
    on.exit(parallel::stopCluster(cl))
    
    bench::mark(
      iterations = 10,
      'abdiv'    = cleanup(pairwise(abdiv::variance_adjusted_unifrac, hmp50_mtx, hmp50_tree)),
      'ecodive'  = cleanup(ecodive::variance_adjusted_unifrac(hmp50_dgC_t, hmp50_tree, margin = 2)) )
  })
)
  

## Data frame for Figure 1A
Fig1A_data <- bind_rows(
    mutate(bray_curtis_res, Metric = 'bray'),
    mutate(shannon_res,     Metric = 'shannon'),
    mutate(faith_res,       Metric = 'faith') ) %>%
  mutate(Package = as.character(expression)) %>%
  select(Package, Metric, median, mem_alloc) %>%
  arrange(Metric, median)

Fig1A_data$Title <- factor(
  x      = Fig1A_data$Metric, 
  levels = c("shannon", "bray", "faith"), 
  labels = c(
    "**Shannon Diversity Index**<br>1006 samples", 
    "**Bray-Curtis Dissimilarity**<br>1006 samples", 
    "**Faith's Phylogenetic Diversity**<br>50 samples") )


## ggplot for Figure 1A
Fig1A <- ggplot(Fig1A_data, aes(x = median, y = mem_alloc)) +
    facet_wrap('Title', nrow = 1, scales = 'free_x') + 
    geom_point() +
    geom_label_repel(aes(
        label    = Package,
        alpha    = ifelse(Package == 'ecodive', 1, 0.6),
        fontface = ifelse(Package == 'ecodive', 2, 1),
        size     = ifelse(Package == 'ecodive', 3.2, 3) ), 
      box.padding        = .4,
      point.padding      = .5,
      min.segment.length = 0 ) + 
    scale_alpha_identity(guide = 'none') +
    scale_size_identity(guide = 'none') +
    bench::scale_x_bench_time() +
    scale_y_log10(labels = scales::label_bytes()) +
    labs(
      tag = 'A',
      x   = 'Median Calculation Time (log scale; n=10)', 
      y   = 'Memory Allocated\n(log scale; n=1)' ) +
    theme_bw(base_size = 12) +
    theme(
      strip.text   = ggtext::element_markdown(hjust = 0, lineheight = 1.2),
      axis.title.x = element_text(margin = margin(t = 10)))
      

## Data frame for Figure 1B
Fig1B_data <- bind_rows(
    mutate(u_unifrac_res,  `UniFrac Variant` = 'Unweighted'),
    mutate(w_unifrac_res,  `UniFrac Variant` = 'Weighted'),
    mutate(wn_unifrac_res, `UniFrac Variant` = 'Weighted Normalized'),
    mutate(g_unifrac_res,  `UniFrac Variant` = 'Generalized'),
    mutate(va_unifrac_res, `UniFrac Variant` = 'Variance Adjusted') ) %>%
  mutate(Package = as.character(expression)) %>%
  select(Package, `UniFrac Variant`, median, mem_alloc) %>%
  arrange(Package)

Fig1B_data$Title <- "**UniFrac Family**<br>50 samples"
Fig1B_data$`UniFrac Variant` <- factor(
  x      = Fig1B_data$`UniFrac Variant`, 
  levels = c("Unweighted", "Weighted", "Weighted Normalized", "Generalized", "Variance Adjusted") )


## ggplot for Figure 1B
Fig1B <- ggplot(Fig1B_data, aes(x = median, y = mem_alloc)) +
  facet_wrap('Title') + 
  geom_point(aes(shape = `UniFrac Variant`), size = 2) +
  geom_label_repel(aes(
      label    = Package, 
      alpha    = ifelse(Package == 'ecodive', 1, 0.6),
      fontface = ifelse(Package == 'ecodive', 2, 1),
      size     = ifelse(Package == 'ecodive', 3.2, 3) ),
    data          = ~subset(., `UniFrac Variant` == 'Unweighted'),
    direction     = 'y', 
    box.padding   = 0.4,
    point.padding = 10,
    min.segment.length = Inf ) + 
  scale_shape(solid = FALSE) + 
  scale_alpha_identity(guide = 'none') +
  scale_size_identity(guide = 'none') +
  bench::scale_x_bench_time() +
  scale_y_log10(labels = scales::label_bytes()) +
  labs(
    tag = 'B',
    x   = 'Median Calculation Time (log scale; n=10)', 
    y   = 'Memory Allocated\n(log scale; n=1)' ) +
  theme_bw(base_size = 12) +
  theme(
    strip.text   = ggtext::element_markdown(hjust = 0, lineheight = 1.2),
    axis.title.x = element_text(margin = margin(t = 10)) )


## Combined Figure 1
Fig1 <- patchwork::wrap_plots(
  Fig1A, 
  Fig1B, 
  patchwork::guide_area(), 
  design = "111\n223", 
  guides = 'collect' )

Results

print(Fig1)

How much faster and more memory efficient is ecodive?

plyr::ddply(Fig1A_data, as.name('Metric'), function (x) {
  x[['median']]    <- as.numeric(x[['median']])
  x[['mem_alloc']] <- as.numeric(x[['mem_alloc']])
  ecodive <- as.list(x[x[['Package']] == 'ecodive',])
  x       <- x[x[['Package']] != 'ecodive',]
  data.frame(
    speed  = paste0(paste(collapse=' - ', round(range(x$median    / ecodive$median))), 'x'),
    memory = paste0(paste(collapse=' - ', round(range(x$mem_alloc / ecodive$mem_alloc))), 'x') )
})

#>    Metric      speed        memory
#> 1    bray  8 - 1259x     2 - 5272x
#> 2   faith  1 - 9290x  168 - 58964x
#> 3 shannon   3 - 159x  1849 - 8261x


plyr::ddply(Fig1B_data, as.name('UniFrac Variant'), function (x) {
  x[['median']]    <- as.numeric(x[['median']])
  x[['mem_alloc']] <- as.numeric(x[['mem_alloc']])
  ecodive <- as.list(x[x[['Package']] == 'ecodive',])
  x       <- x[x[['Package']] != 'ecodive',]
  data.frame(
    speed  = paste0(paste(collapse=' - ', round(range(x$median    / ecodive$median))), 'x'),
    memory = paste0(paste(collapse=' - ', round(range(x$mem_alloc / ecodive$mem_alloc))), 'x') )
})
#>       UniFrac Variant         speed            memory
#> 1          Unweighted     1 - 2264x       74 - 29695x
#> 2            Weighted    45 - 2019x     421 - 175550x
#> 3 Weighted Normalized    12 - 2138x     422 - 175629x
#> 4         Generalized    10 - 1818x     673 - 151011x
#> 5   Variance Adjusted  2314 - 2314x  216462 - 216462x

Raw Data for Figure 1 Panel A

print(Fig1A_data[,1:4], n = Inf)
#> # A tibble: 21 × 4
#>    Package      Metric    median mem_alloc
#>    <chr>        <chr>   <bch:tm> <bch:byt>
#>  1 ecodive      bray     19.54ms    3.97MB
#>  2 philentropy  bray    150.69ms   38.87MB
#>  3 parallelDist bray    187.98ms    7.88MB
#>  4 ecodist      bray    399.37ms   29.45MB
#>  5 labdsv       bray    723.36ms   68.16MB
#>  6 vegan        bray       1.68s   16.45MB
#>  7 abdiv        bray      13.68s   20.43GB
#>  8 tabula       bray      24.59s   20.44GB
#>  9 phyloregion  faith      3.1ms  145.18MB
#> 10 ecodive      faith     3.14ms  425.89KB
#> 11 picante      faith    83.91ms   69.86MB
#> 12 abdiv        faith   624.58ms  651.74MB
#> 13 adiv         faith      2.03s  562.76MB
#> 14 entropart    faith     29.13s   23.95GB
#> 15 ecodive      shannon   8.19ms    15.6KB
#> 16 tabula       shannon  24.41ms   28.17MB
#> 17 entropart    shannon  36.85ms   41.77MB
#> 18 adiv         shannon  38.68ms  125.87MB
#> 19 vegan        shannon  58.97ms   68.08MB
#> 20 abdiv        shannon  65.92ms   95.38MB
#> 21 philentropy  shannon     1.3s   52.67MB

Raw Data for Figure 1 Panel B

print(Fig1B_data[,1:4], n = Inf)
#> # A tibble: 21 × 4
#>    Package     `UniFrac Variant`     median mem_alloc
#>    <chr>       <fct>               <bch:tm> <bch:byt>
#>  1 GUniFrac    Unweighted           77.53ms   113.4MB
#>  2 GUniFrac    Weighted Normalized  88.74ms    92.1MB
#>  3 GUniFrac    Generalized          80.09ms    92.1MB
#>  4 abdiv       Unweighted             14.5s    20.1GB
#>  5 abdiv       Weighted              15.74s      20GB
#>  6 abdiv       Weighted Normalized   16.17s      20GB
#>  7 abdiv       Generalized           15.01s    20.2GB
#>  8 abdiv       Variance Adjusted        17s    24.5GB
#>  9 ampvis2     Unweighted             3.47s    53.5MB
#> 10 ampvis2     Weighted               4.48s    49.2MB
#> 11 ampvis2     Weighted Normalized    4.34s    49.3MB
#> 12 ecodive     Unweighted             6.4ms   708.2KB
#> 13 ecodive     Weighted               7.8ms   119.6KB
#> 14 ecodive     Weighted Normalized   7.56ms   119.6KB
#> 15 ecodive     Generalized           8.26ms   140.2KB
#> 16 ecodive     Variance Adjusted     7.35ms   118.5KB
#> 17 phyloregion Unweighted            6.27ms   149.5MB
#> 18 phyloseq    Unweighted          297.66ms    50.9MB
#> 19 phyloseq    Weighted            352.09ms    49.4MB
#> 20 phyloseq    Weighted Normalized 415.88ms    49.5MB
#> 21 picante     Unweighted             2.54s     1.8GB