3  Alpha diversity

Alpha diversity describes the diversity within a single sample: how many taxa are there, and how evenly are the reads distributed among them? Three measures are commonly reported together because they capture different aspects:

  1. Observed richness : the number of ASVs with at least one read. Simple but sensitive to sequencing depth.
  2. Shannon index : combines richness and evenness into a single number. Less sensitive to depth than observed richness, but still not immune to it.
  3. Pielou’s evenness : Shannon divided by log(observed richness). Tells you how evenly distributed the community is, independent of how many taxa it contains.

In this dataset we expect a clear pattern: the L. plantarum IBB082 inoculation should rapidly drive the community toward dominance by Lactiplantibacillus, collapsing diversity and evenness. Spontaneous fermentations should retain higher diversity throughout. Both should show some change over the four time points (H24, H48, W1, W2).

4 Setup

Code
library(phyloseq)
library(microbiome)
library(dplyr)
library(tidyr)
library(tibble)
library(ggplot2)

5 Load the filtered phyloseq object

Alpha diversity is computed on the filtered count object, not on the relative abundance object. The metrics work on integer counts.

Code
ps_filt <- readRDS("phyloseq_filtered.rds")
ps_filt

6 Step 1: Compute alpha diversity

The microbiome::alpha() function returns a single dataframe with many indices in one call. We will use a curated subset.

Code
alpha_df <- microbiome::alpha(
  ps_filt,
  index = c("observed", "diversity_shannon", "evenness_pielou")
)

# microbiome::alpha returns rownames as sample IDs — bring them in as a column
alpha_df <- alpha_df %>%
  rownames_to_column("sample_alias")

head(alpha_df)

A note on the index names. microbiome::alpha() uses prefixed names like diversity_shannon and evenness_pielou so that related indices group together alphabetically. The function supports many more indices than the three used here (Simpson, inverse Simpson, Chao1, several rarity and dominance metrics); see ?microbiome::alpha for the full list.

6.1 Attach the sample metadata

To plot or test the diversity metrics across experimental groups, we need to merge them with the sample metadata.

Code
meta_df <- microbiome::meta(ps_filt) %>%
  rownames_to_column("sample_alias")

alpha_df <- alpha_df %>%
  left_join(meta_df, by = "sample_alias")

7 Step 2: Visualize the patterns

A faceted boxplot is the clearest way to see all three metrics at once across the experimental design.

Code
alpha_long <- alpha_df %>%
  pivot_longer(
    cols = c(observed, diversity_shannon, evenness_pielou),
    names_to  = "Metric",
    values_to = "Value"
  ) %>%
  # Friendly facet labels and a sensible ordering
  mutate(Metric = recode(Metric,
    observed          = "Observed ASVs",
    diversity_shannon = "Shannon",
    evenness_pielou   = "Pielou's evenness"
  )) %>%
  mutate(Metric = factor(Metric,
    levels = c("Observed ASVs", "Shannon", "Pielou's evenness")
  )) %>%
  # Replace NA for commercial and control
  mutate(Time_point=ifelse(Fermentation=="Control", "Ctrl", 
                           ifelse(Fermentation=="Commercial", "Com", Time_point)))

ggplot(alpha_long, aes(x = Time_point, y = Value, fill = Fermentation)) +
  geom_boxplot(outlier.shape = NA, alpha = 0.7) +
  geom_point(position = position_jitterdodge(jitter.width = 0.1), size = 1.5) +
  facet_wrap(~ Metric, scales = "free_y") +
  labs(x = NULL, y = NULL, fill = "Fermentation type") +
  theme_bw() +
  theme(legend.position = "bottom")

What to look for:

  1. The Lactobacillus-inoculated group should sit much lower on all three metrics than the spontaneous group, at every time point. The effect should be visible immediately at H24 and persist throughout.
  2. The spontaneous group may show some drift across time points, richness can decrease as competitive lactic acid bacteria become established, but the magnitude is much smaller than the inoculation effect.
  3. Pielou’s evenness usually shows the cleanest separation, because it removes the influence of total ASV count.

8 Step 3: Statistical testing

When the visual signal is this strong, a formal test is more about quantifying the effect than discovering it. Two practical points before we run anything:

  1. Sample size constraints. With n = 3 per group per time point, the Wilcoxon rank-sum test cannot produce a p-value below ~0.1 regardless of how separated the groups are. Per-timepoint tests are therefore underpowered by design. Combining across time points (n = 12 vs n = 12) restores enough power to detect the overall effect.
  2. The data are not independent across time points. Each jar contributes one sample at each time point. Strictly speaking this calls for a mixed model with jar as a random effect. For the workshop we treat the time points as independent, which is conservative for the overall fermentation-type comparison but would be wrong for testing time effects within a fermentation type.
Code
# Overall comparison: Spontaneous vs Lactobacillus, pooling time points.
# Restrict to the two main fermentation types; drop commercial and
# control samples for this comparison.
alpha_test <- alpha_df %>%
  filter(Fermentation %in% c("Spontaneous", "Lactobacillus"))

wilcox.test(diversity_shannon ~ Fermentation, data = alpha_test)
wilcox.test(observed          ~ Fermentation, data = alpha_test)
wilcox.test(evenness_pielou   ~ Fermentation, data = alpha_test)

The expected outcome is a strongly significant difference for all three metrics. Report the effect size (medians or means per group) alongside the p-value, the p-value alone is uninformative when the design guarantees a strong result.

Code
alpha_test %>%
  group_by(Fermentation) %>%
  summarise(
    n            = n(),
    mean_observed = mean(observed),
    mean_shannon  = mean(diversity_shannon),
    mean_pielou   = mean(evenness_pielou)
  )

Why no per-timepoint tests? As noted above, n = 3 per group is below the threshold at which Wilcoxon can reject the null. If per-timepoint comparisons are scientifically important in your own work, options include increasing replication, using a parametric test if the metric is approximately normal (e.g. t-test on Shannon), or fitting a model that uses information across time points jointly (e.g. linear model with Time_point * Fermentation, or a mixed model if there is repeated measurement structure).

9 Step 4: Save the alpha diversity table

It is useful to keep the alpha diversity table as a separate file rather than recomputing it later — for example to include in a report or join with other sample-level measurements.

Code
write_csv(alpha_df, "alpha_diversity.csv")

10 Take-home points

  1. Alpha diversity has three faces: richness, evenness, and the Shannon index that combines them. Report all three when you can.
  2. microbiome::alpha() computes many indices in one call and returns a tidy dataframe ready to merge with metadata.
  3. Choice of statistical test must match the design. With small per-group n, pool when possible and accept that per-group tests will be underpowered. Visual inspection is often the strongest evidence.
  4. Effect sizes (means or medians) belong next to every p-value, and are more interpretable than the p-value when the design pre-determines the result.

11 Optional exercises

  1. Compute Simpson’s diversity index in addition to Shannon. How does it compare? In what circumstances would you prefer Simpson over Shannon?
  2. Rarefy the filtered phyloseq object to the smallest sample’s depth using phyloseq::rarefy_even_depth(ps_filt, sample.size = min(sample_sums(ps_filt)), rngseed = 42). Recompute observed richness, Shannon, and Pielou’s evenness. How do the conclusions compare to the unrarefied analysis? Try with two different random seeds, do you get the same numerical values?