-
Notifications
You must be signed in to change notification settings - Fork 56
docs: Add comprehensive Rarefaction section to transformation chapter #825
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: devel
Are you sure you want to change the base?
Changes from all commits
74129d5
bb466b1
f067bbb
6edacc4
d93a900
c9ea5b5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -146,6 +146,119 @@ than the minimum abundance value before transformation. Some tools, like | |
| values. See [@sec-differential-abundance]. | ||
| ::: | ||
|
|
||
| ## Rarefaction {#sec-rarefaction} | ||
|
|
||
| Another approach to control uneven sampling depths is to apply rarefaction with `rarefyAssay()`, which resamples the samples to an equal number of reads. This remains controversial, however, and strategies to mitigate the information loss in rarefaction have been proposed [@Schloss_2024a; @Schloss_2024b]. Moreover, this practice has been discouraged for the analysis of differentially abundant microorganisms [@McMurdie_and_Holmes_2014]. | ||
|
|
||
| Rarefaction can be performed iteratively by using the `niter` parameter in `rarefyAssay()`. This creates multiple rarefied versions of the data, which can help account for the stochasticity introduced by random subsampling. The resulting rarefied assays can then be used for downstream analyses such as alpha and beta diversity calculations. For alpha and beta diversity, the same repeated subsampling can also be done directly within `addAlpha()` and `addMDS()` by setting `niter`. | ||
|
|
||
| ### Using rarefaction with alpha diversity | ||
|
|
||
| When calculating alpha diversity indices, you can first create rarefied assays with `rarefyAssay()` and reuse them later. This is useful when you want to inspect or store the rarefied data itself: | ||
|
|
||
| ```{r} | ||
| #| label: rarefaction-alpha | ||
| #| eval: true | ||
|
|
||
| # Load example data | ||
| library(mia) | ||
| data("Tengeler2020") | ||
| tse <- Tengeler2020 | ||
|
|
||
| # Get minimum read depth for rarefaction | ||
| min_reads <- min(colSums(assay(tse, "counts"))) | ||
|
|
||
| # Perform iterative rarefaction | ||
| tse <- rarefyAssay( | ||
| tse, | ||
| method = "subsample", | ||
| sample = min_reads, | ||
| niter = 100 | ||
| ) | ||
| ``` | ||
|
|
||
| If you only need alpha diversity, `addAlpha()` can do the iterative subsampling directly from the count assay. It stores the values in the object, while `getAlpha()` returns them separately: | ||
|
|
||
| ```{r} | ||
| #| label: rarefaction-alpha-direct | ||
| #| eval: true | ||
|
|
||
| # Reload example data so this chunk is self-contained. | ||
| library(mia) | ||
| data("Tengeler2020") | ||
| tse <- Tengeler2020 | ||
|
|
||
| # Calculate alpha diversity with iterative rarefaction | ||
| tse <- addAlpha( | ||
| tse, | ||
| assay.type = "counts", | ||
| index = "shannon", | ||
| niter = 100 | ||
| ) | ||
| ``` | ||
|
|
||
| ### Using rarefaction with beta diversity | ||
|
|
||
| Similarly, rarefaction can be applied before calculating beta diversity and performing ordination. If you want to store a rarefied assay first, `rarefyAssay()` still works as above. For ordination, `addMDS()` can also perform the repeated subsampling directly from the count assay: | ||
|
|
||
| ```{r} | ||
| #| label: rarefaction-beta | ||
| #| eval: true | ||
|
|
||
| # Reload example data so this chunk is self-contained. | ||
| library(mia) | ||
| data("Tengeler2020") | ||
| tse <- Tengeler2020 | ||
|
|
||
| # Perform MDS ordination with iterative rarefaction | ||
| tse <- addMDS( | ||
| tse, | ||
| assay.type = "counts", | ||
| method = "bray", | ||
| niter = 100 | ||
| ) | ||
| ``` | ||
|
|
||
| When you combine iterative rarefaction with a transformation, keep the input as counts and pass the transformation through `transf` instead of pre-transforming the assay. The same pattern can be used for different transformations by swapping the helper function, for example a relative-abundance or clr-style transformation. | ||
|
|
||
| ```{r} | ||
| #| label: rarefaction-beta-transf | ||
| #| eval: true | ||
|
|
||
| # Reload example data so this chunk is self-contained. | ||
| library(mia) | ||
| library(vegan) | ||
| data("Tengeler2020") | ||
| tse <- Tengeler2020 | ||
|
|
||
| # Define a custom transformation function. | ||
| clr <- function(x) { | ||
| vegan::decostand(x, method = "clr", pseudocount = 1) | ||
| } | ||
|
|
||
| # Apply the transformation after rarefaction and before the beta diversity calculation. | ||
| tse <- addMDS( | ||
| tse, | ||
| assay.type = "counts", | ||
| FUN = getDissimilarity, | ||
| method = "euclidean", | ||
| niter = 100, | ||
| sample = min(colSums(assay(tse, "counts"))), | ||
| transf = clr, | ||
| replace = TRUE, | ||
| name = "MDS_clr_rarefied" | ||
| ) | ||
| ``` | ||
|
|
||
| ### Function comparison | ||
|
|
||
| **`addAlpha()` vs `getAlpha()`**: Both functions calculate alpha diversity indices, but `addAlpha()` stores the results directly into the `colData` of the TreeSummarizedExperiment object, while `getAlpha()` returns the diversity values as a separate vector or matrix. Use `addAlpha()` when you want to keep all data together in one object, and `getAlpha()` when you need the diversity values for immediate use in other calculations. | ||
|
|
||
|
Comment on lines
+255
to
+256
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest to explain this earlier, where the rarified alpha diversity analysis is shown. |
||
| **`runMDS()` vs `addMDS()`**: The `runMDS()` function calculates multidimensional scaling coordinates and returns them as a separate matrix, whereas `addMDS()` calculates the MDS coordinates and stores them directly into the `reducedDim` slot of the TreeSummarizedExperiment object. Using `addMDS()` is generally preferred as it maintains all results within the same data object, making downstream analyses and visualization more straightforward. | ||
|
|
||
|
Comment on lines
+257
to
+258
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could also comment whether this is available for other ordination functions e.g. runPCA, runNMDS..? |
||
| The same add/get pattern is also used for other ordination workflows where available, for example `runNMDS()` / `addNMDS()` in the community similarity chapter. | ||
|
|
||
|
|
||
| ## Transformations in practice | ||
|
|
||
| Below, we apply relative transformation to counts table. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addAlphacan be used independently ofrarefyAssay.Hence I am thinking that it might be more clear to show these as two separate operations that can both be feasible but each on their own right. Shall we split this chunk in two parts?