This vignette contains a detailed tutorial on how to train a MOFA model using R. A concise template script can be found here. Many more examples on application of MOFA to various multi-omics data sets can be found here.
MOFA (and factor analysis models in general) are useful to uncover variation in complex data sets that contain multiple sources of heterogeneity. This requires a relatively large sample size (at least ~15 samples). In addition, MOFA needs the multi-modal measurements to be derived from the same samples. It is fine if you have samples that are missing some data modality, but there has to be a significant degree of matched measurements.
Proper normalisation of the data is critical. The model can handle three types of data: continuous (modelled with a gaussian likelihood), small counts (modelled with a Poisson likelihood) and binary measurements (modelled with a bernoulli likelihood). Non-gaussian likelihoods give non-optimal results, we recommend the user to apply data transformations to obtain continuous measurements. For example, for count-based data such as RNA-seq or ATAC-seq we recommend size factor normalisation + variance stabilisation (i.e. a log transformation).
It is strongly recommended that you select highly variable features (HVGs) per assay before fitting the model. This ensures a faster training and a more robust inference procedure. Also, for data modalities that have very different dimensionalities we suggest a stronger feature selection fort he bigger views, with the aim of reducing the feature imbalance between data modalities.
To create a MOFA object you need to specify three dimensions: samples, features and view(s). Optionally, a group can also be specified for each sample (no group structure by default). MOFA objects can be created from a wide range of input formats, including:
A list of matrices, where each entry corresponds to one view. Samples are stored in columns and features in rows.
Let’s simulate some data to start with
data <- make_example_data(
n_views = 2,
n_samples = 200,
n_features = 1000,
n_factors = 10
)[[1]]
lapply(data,dim)
## $view_1
## [1] 1000 200
##
## $view_2
## [1] 1000 200
Create the MOFA object:
Plot the data overview
In case you are using the multi-group functionality, the groups can
be specified using the groups
argument as a vector with the
group ID for each sample. Keep in mind that the multi-group
functionality is a rather advanced option that we discourage for
beginners. For more details on how the multi-group inference works, read
the FAQ section
and check
this vignette.
N = ncol(data[[1]])
groups = c(rep("A",N/2), rep("B",N/2))
MOFAobject <- create_mofa(data, groups=groups)
Plot the data overview
A long data.frame with columns sample
,
feature
, view
, group
(optional),
value
might be the best format for complex data sets with
multiple omics and potentially multiple groups of data. Also, there is
no need to add rows that correspond to missing data:
## sample feature view value
## <char> <char> <char> <num>
## 1: sample_0_group_1 feature_0_view_0 view_0 2.08
## 2: sample_1_group_1 feature_0_view_0 view_0 0.01
## 3: sample_2_group_1 feature_0_view_0 view_0 -0.11
## 4: sample_3_group_1 feature_0_view_0 view_0 -0.82
## 5: sample_4_group_1 feature_0_view_0 view_0 -1.13
## 6: sample_5_group_1 feature_0_view_0 view_0 -0.25
Create the MOFA object
## Creating MOFA object from a data.frame...
## Untrained MOFA model with the following characteristics:
## Number of views: 2
## Views names: view_0 view_1
## Number of features (per view): 1000 1000
## Number of groups: 1
## Groups names: single_group
## Number of samples (per group): 100
##
Plot data overview
FALSE
FALSE
## $scale_views
## [1] FALSE
##
## $scale_groups
## [1] FALSE
##
## $center_groups
## [1] TRUE
##
## $use_float32
## [1] TRUE
##
## $views
## [1] "view_0" "view_1"
##
## $groups
## [1] "single_group"
FALSE
.TRUE
.TRUE
if using multiple groups.TRUE
if using multiple views.Only change the default model options if you are familiar with the underlying mathematical model.
## $likelihoods
## view_0 view_1
## "gaussian" "gaussian"
##
## $num_factors
## [1] 10
##
## $spikeslab_factors
## [1] FALSE
##
## $spikeslab_weights
## [1] FALSE
##
## $ard_factors
## [1] FALSE
##
## $ard_weights
## [1] TRUE
## $maxiter
## [1] 1000
##
## $convergence_mode
## [1] "fast"
##
## $drop_factor_threshold
## [1] -1
##
## $verbose
## [1] FALSE
##
## $startELBO
## [1] 1
##
## $freqELBO
## [1] 5
Prepare the MOFA object
MOFAobject <- prepare_mofa(
object = MOFAobject,
data_options = data_opts,
model_options = model_opts,
training_options = train_opts
)
Train the MOFA model. Remember that in this step the
MOFA2
R package connets with the mofapy2
Python package using reticulate
. This is the source of most
problems when running MOFA. See our FAQ section if you
have issues. The output is saved in the file specified as
outfile
. If none is specified, the output is saved in a
temporary location.
outfile = file.path(tempdir(),"model.hdf5")
MOFAobject.trained <- run_mofa(MOFAobject, outfile, use_basilisk=TRUE)
## Warning: Output file /tmp/RtmpwTXRID/model.hdf5 already exists, it will be replaced
## Connecting to the mofapy2 package using basilisk.
## Set 'use_basilisk' to FALSE if you prefer to manually set the python binary using 'reticulate'.
If everything is successful, you should observe an output analogous to the following:
######################################
## Training the model with seed 1 ##
######################################
Iteration 1: time=0.03, ELBO=-52650.68, deltaELBO=837116.802 (94.082647669%), Factors=10
(...)
Iteration 9: time=0.04, ELBO=-50114.43, deltaELBO=23.907 (0.002686924%), Factors=10
#######################
## Training finished ##
#######################
Saving model in `/var/folders/.../model.hdf5.../tmp/RtmpwTXRID/model.hdf5.
This finishes the tutorial on how to train a MOFA object from R. To continue with the downstream analysis, follow this tutorial
## R version 4.4.1 (2024-06-14)
## Platform: x86_64-pc-linux-gnu
## Running under: Ubuntu 24.04.1 LTS
##
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
## LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so; LAPACK version 3.12.0
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=en_US.UTF-8 LC_COLLATE=C
## [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
## [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
## [9] LC_ADDRESS=C LC_TELEPHONE=C
## [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
##
## time zone: Etc/UTC
## tzcode source: system (glibc)
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] data.table_1.16.2 pheatmap_1.0.12 lubridate_1.9.3 forcats_1.0.0
## [5] stringr_1.5.1 dplyr_1.1.4 purrr_1.0.2 readr_2.1.5
## [9] tidyr_1.3.1 tibble_3.2.1 ggplot2_3.5.1 tidyverse_2.0.0
## [13] MOFA2_1.17.0 BiocStyle_2.35.0
##
## loaded via a namespace (and not attached):
## [1] rlang_1.1.4 magrittr_2.0.3 RcppAnnoy_0.0.22
## [4] matrixStats_1.4.1 compiler_4.4.1 mgcv_1.9-1
## [7] dir.expiry_1.15.0 png_0.1-8 vctrs_0.6.5
## [10] reshape2_1.4.4 pkgconfig_2.0.3 crayon_1.5.3
## [13] fastmap_1.2.0 backports_1.5.0 XVector_0.45.0
## [16] labeling_0.4.3 utf8_1.2.4 rmarkdown_2.28
## [19] tzdb_0.4.0 xfun_0.48 zlibbioc_1.51.2
## [22] cachem_1.1.0 jsonlite_1.8.9 highr_0.11
## [25] rhdf5filters_1.17.0 DelayedArray_0.33.1 Rhdf5lib_1.27.0
## [28] broom_1.0.7 irlba_2.3.5.1 parallel_4.4.1
## [31] R6_2.5.1 bslib_0.8.0 stringi_1.8.4
## [34] RColorBrewer_1.1-3 reticulate_1.39.0 GGally_2.2.1
## [37] car_3.1-3 jquerylib_0.1.4 Rcpp_1.0.13
## [40] knitr_1.48 IRanges_2.39.2 Matrix_1.7-1
## [43] splines_4.4.1 timechange_0.3.0 tidyselect_1.2.1
## [46] abind_1.4-8 yaml_2.3.10 codetools_0.2-20
## [49] lattice_0.22-6 plyr_1.8.9 basilisk.utils_1.19.0
## [52] withr_3.0.2 evaluate_1.0.1 Rtsne_0.17
## [55] ggstats_0.7.0 pillar_1.9.0 BiocManager_1.30.25
## [58] ggpubr_0.6.0 filelock_1.0.3 MatrixGenerics_1.17.1
## [61] carData_3.0-5 corrplot_0.95 stats4_4.4.1
## [64] generics_0.1.3 S4Vectors_0.43.2 hms_1.1.3
## [67] munsell_0.5.1 scales_1.3.0 glue_1.8.0
## [70] maketools_1.3.1 tools_4.4.1 sys_3.4.3
## [73] ggsignif_0.6.4 buildtools_1.0.0 mvtnorm_1.3-1
## [76] cowplot_1.1.3 rhdf5_2.49.0 grid_4.4.1
## [79] colorspace_2.1-1 nlme_3.1-166 basilisk_1.19.0
## [82] HDF5Array_1.33.8 Formula_1.2-5 cli_3.6.3
## [85] fansi_1.0.6 S4Arrays_1.5.11 uwot_0.2.2
## [88] gtable_0.3.6 rstatix_0.7.2 sass_0.4.9
## [91] digest_0.6.37 BiocGenerics_0.53.0 SparseArray_1.5.45
## [94] ggrepel_0.9.6 farver_2.1.2 htmltools_0.5.8.1
## [97] lifecycle_1.0.4