# Gene regulatory network inference

Fabricio Almeida-Silva1 and Thiago Motta Venancio1

1Universidade Estadual do Norte Fluminense Darcy Ribeiro, RJ, Brazil

#### 15 April 2025

# Contents

# 1 Installation

    if(!requireNamespace('BiocManager', quietly = TRUE))
      install.packages('BiocManager')

    BiocManager::install("BioNERO")

    # Load package after installation
    library(BioNERO)
    set.seed(123) # for reproducibility

# 2 Introduction and algorithm description

In the previous vignette, we explored all aspects of gene coexpression networks (GCNs), which are represented as undirected weighted graphs. It is undirected because, for a given link between gene A and gene B, we can only say that these genes are coexpressed, but we cannot know whether gene A controls gene B or otherwise. Further, weighted means that some coexpression relationships between gene pairs are stronger than others. In this vignette, we will demonstrate how to infer gene regulatory networks (GRNs) from expression data with BioNERO. GRNs display interactions between regulators (e.g., transcription factors or miRNAs) and their targets (e.g., genes). Hence, they are represented as directed unweighted graphs.

Numerous algorithms have been developed to infer GRNs from expression data. However, the algorithm performances are highly dependent on the benchmark data set. To solve this uncertainty, Marbach et al. (2012) proposed the application of the “wisdom of the crowds” principle to GRN inference. This approach consists in inferring GRNs with different algorithms, ranking the interactions identified by each method, and calculating the average rank for each interaction across all algorithms used. This way, we can have consensus, high-confidence edges to be used in biological interpretations. For that, `BioNERO` implements three popular algorithms: GENIE3 (Huynh-Thu et al. 2010), ARACNE (Margolin et al. 2006) and CLR (Faith et al. 2007).

# 3 Data preprocessing

Before inferring the GRN, we will preprocess the expression data the same way we did in the previous vignette.

    # Load example data set
    data(zma.se)

    # Preprocess the expression data
    final_exp <- exp_preprocess(
        zma.se,
        min_exp = 10,
        variance_filter = TRUE,
        n = 2000
    )
    ## Number of removed samples: 1

# 4 Gene regulatory network inference

`BioNERO` requires only 2 objects for GRN inference: the expression data (SummarizedExperiment, matrix or data frame) and a character vector of regulators (transcription factors or miRNAs). The transcription factors used in this vignette were downloaded from PlantTFDB 4.0 (Jin et al. 2017).

    data(zma.tfs)
    head(zma.tfs)
    ##              Gene Family
    ## 6  Zm00001d022525    Dof
    ## 25 Zm00001d037605   GATA
    ## 28 Zm00001d049540    NAC
    ## 45 Zm00001d042287    MYB
    ## 46 Zm00001d042288    NAC
    ## 54 Zm00001d039371    TCP

## 4.1 Consensus GRN inference

Inferring GRNs based on the wisdom of the crowds principle can be done with a single function: `exp2grn()`. This function will infer GRNs with GENIE3, ARACNE and CLR, calculate average ranks for each interaction and filter the resulting network based on the optimal scale-free topology (SFT) fit. In the filtering step, n different networks are created by subsetting the top n quantiles. For instance, if a network of 10,000 edges is given as input with `nsplit = 10`, 10 different networks will be created: the first with 1,000 edges, the second with 2,000 edges, and so on, with the last network being the original input network. Then, for each network, the function will calculate the SFT fit and select the best fit.

    # Using 10 trees for demonstration purposes. Use the default: 1000
    grn <- exp2grn(
        exp = final_exp,
        regulators = zma.tfs$Gene,
        nTrees = 10
    )
    ## The top number of edges that best fits the scale-free topology is 247
    head(grn)
    ##          Regulator         Target
    ## 291 Zm00001d041474 Zm00001d027374
    ## 304 Zm00001d042263 Zm00001d045042
    ## 280 Zm00001d041474 Zm00001d006602
    ## 281 Zm00001d041474 Zm00001d006942
    ## 289 Zm00001d041474 Zm00001d018668
    ## 145 Zm00001d028432 Zm00001d014349

## 4.2 Algorithm-specific GRN inference

This section is directed to users who, for some reason (e.g., comparison, exploration), want to infer GRNs with particular algorithms. The available algorithms are:

GENIE3: a regression-tree based algorithm that decomposes the prediction of GRNs for n genes into n regression problems. For each regression problem, the expression profile of a target gene is predicted from the expression profiles of all other genes using random forests (default) or extra-trees.

    # Using 10 trees for demonstration purposes. Use the default: 1000
    genie3 <- grn_infer(
        final_exp,
        method = "genie3",
        regulators = zma.tfs$Gene,
        nTrees = 10)
    head(genie3)
    ##                Node1          Node2    Weight
    ## 49836 Zm00001d039989 Zm00001d043942 0.4559930
    ## 37975 Zm00001d030617 Zm00001d034368 0.4293781
    ## 34029 Zm00001d038832 Zm00001d031640 0.4287395
    ## 8526  Zm00001d045323 Zm00001d008594 0.4084538
    ## 39247 Zm00001d045323 Zm00001d035094 0.4084167
    ## 34629 Zm00001d052229 Zm00001d031963 0.3899265
    dim(genie3)
    ## [1] 60140     3

ARACNE: information-theoretic algorithm that aims to remove indirect interactions inferred by coexpression.

    aracne <- grn_infer(final_exp, method = "aracne", regulators = zma.tfs$Gene)
    head(aracne)
    ##                Node1          Node2   Weight
    ## 23861 Zm00001d038832 Zm00001d021147 1.789818
    ## 1758  Zm00001d038832 Zm00001d000432 1.692232
    ## 11337 Zm00001d038832 Zm00001d011086 1.692232
    ## 27014 Zm00001d011139 Zm00001d024274 1.674840
    ## 51070 Zm00001d011139 Zm00001d045069 1.658043
    ## 28387 Zm00001d038832 Zm00001d025784 1.641802
    dim(aracne)
    ## [1] 411   3

CLR: extension of the relevance networks algorithm that uses mutual information to identify regulatory interactions.

    clr <- grn_infer(final_exp, method = "clr", regulators = zma.tfs$Gene)
    head(clr)
    ##                Node1          Node2   Weight
    ## 26302 Zm00001d046937 Zm00001d023376 12.70216
    ## 11267 Zm00001d046937 Zm00001d011080 12.25336
    ## 12540 Zm00001d041474 Zm00001d012007 10.74023
    ## 51019 Zm00001d042263 Zm00001d045042 10.50925
    ## 17810 Zm00001d041474 Zm00001d015811 10.33216
    ## 29278 Zm00001d046937 Zm00001d026632 10.20075
    dim(clr)
    ## [1] 26657     3

Users can also infer GRNs with the 3 algorithms at once using the function `exp_combined()`. The resulting edge lists are stored in a list of 3 elements.1 1 1 NOTE: Under the hood, `exp2grn()` uses `exp_combined()` followed by averaging ranks with `grn_average_rank()` and filtering with `grn_filter()`.

    grn_list <- grn_combined(final_exp, regulators = zma.tfs$Gene, nTrees = 10)
    head(grn_list$genie3)
    ##                Node1          Node2    Weight
    ## 12013 Zm00001d041474 Zm00001d011541 0.4629469
    ## 22057 Zm00001d041474 Zm00001d018986 0.4020641
    ## 22456 Zm00001d028432 Zm00001d019479 0.3941906
    ## 21133 Zm00001d038832 Zm00001d018403 0.3926708
    ## 56194 Zm00001d038832 Zm00001d049552 0.3923130
    ## 45622 Zm00001d036148 Zm00001d040163 0.3895359
    head(grn_list$aracne)
    ##                Node1          Node2   Weight
    ## 23861 Zm00001d038832 Zm00001d021147 1.789818
    ## 1758  Zm00001d038832 Zm00001d000432 1.692232
    ## 11337 Zm00001d038832 Zm00001d011086 1.692232
    ## 27014 Zm00001d011139 Zm00001d024274 1.674840
    ## 51070 Zm00001d011139 Zm00001d045069 1.658043
    ## 28387 Zm00001d038832 Zm00001d025784 1.641802
    head(grn_list$clr)
    ##                Node1          Node2   Weight
    ## 26302 Zm00001d046937 Zm00001d023376 12.70216
    ## 11267 Zm00001d046937 Zm00001d011080 12.25336
    ## 12540 Zm00001d041474 Zm00001d012007 10.74023
    ## 51019 Zm00001d042263 Zm00001d045042 10.50925
    ## 17810 Zm00001d041474 Zm00001d015811 10.33216
    ## 29278 Zm00001d046937 Zm00001d026632 10.20075

# 5 Gene regulatory network analysis

After inferring the GRN, `BioNERO` allows users to perform some common downstream analyses.

## 5.1 Hub gene identification

GRN hubs are defined as the top 10% most highly connected regulators, but this percentile is flexible in `BioNERO`.2 2 2 NOTE: Remember: GRNs are represented as directed graphs. This implies that only regulators are taken into account when identifying hubs. The goal here is to identify regulators (e.g., transcription factors) that control the expression of several genes. They can be identified with `get_hubs_grn()`.

    hubs <- get_hubs_grn(grn)
    hubs
    ##              Gene Degree
    ## 1  Zm00001d038832     19
    ## 2  Zm00001d041474     13
    ## 3  Zm00001d025339     11
    ## 4  Zm00001d046937     11
    ## 5  Zm00001d052229     11
    ## 6  Zm00001d010227     11
    ## 7  Zm00001d030617     11
    ## 8  Zm00001d039989     10
    ## 9  Zm00001d038227     10
    ## 10 Zm00001d011139      9
    ## 11 Zm00001d044315      9
    ## 12 Zm00001d028974      9
    ## 13 Zm00001d013777      9
    ## 14 Zm00001d003822      8
    ## 15 Zm00001d046568      8
    ## 16 Zm00001d020020      7
    ## 17 Zm00001d014377      7
    ## 18 Zm00001d034751      7
    ## 19 Zm00001d054038      7
    ## 20 Zm00001d031655      6
    ## 21 Zm00001d042267      6
    ## 22 Zm00001d036148      6
    ## 23 Zm00001d018081      6
    ## 24 Zm00001d035440      6
    ## 25 Zm00001d027957      6
    ## 26 Zm00001d042263      5
    ## 27 Zm00001d002654      5

## 5.2 Network visualization

    plot_grn(grn)

GRNs can also be visualized interactively for exploratory purposes.

    plot_grn(grn, interactive = TRUE, dim_interactive = c(500,500))

Finally, `BioNERO` can also be used for visualization and hub identification in protein-protein (PPI) interaction networks. The functions `get_hubs_ppi()` and `plot_ppi()` work the same way as their equivalents for GRNs (`get_hubs_grn()` and `plot_grn()`).

# Session information

This vignette was created under the following conditions:

    sessionInfo()
    ## R version 4.5.0 RC (2025-04-04 r88126 ucrt)
    ## Platform: x86_64-w64-mingw32/x64
    ## Running under: Windows Server 2022 x64 (build 20348)
    ##
    ## Matrix products: default
    ##   LAPACK version 3.12.1
    ##
    ## locale:
    ## [1] LC_COLLATE=C
    ## [2] LC_CTYPE=English_United States.utf8
    ## [3] LC_MONETARY=English_United States.utf8
    ## [4] LC_NUMERIC=C
    ## [5] LC_TIME=English_United States.utf8
    ##
    ## time zone: America/New_York
    ## tzcode source: internal
    ##
    ## attached base packages:
    ## [1] stats     graphics  grDevices utils     datasets  methods   base
    ##
    ## other attached packages:
    ## [1] BioNERO_1.16.0   BiocStyle_2.36.0
    ##
    ## loaded via a namespace (and not attached):
    ##   [1] RColorBrewer_1.1-3          ggdendro_0.2.0
    ##   [3] rstudioapi_0.17.1           jsonlite_2.0.0
    ##   [5] shape_1.4.6.1               NetRep_1.2.7
    ##   [7] magrittr_2.0.3              magick_2.8.6
    ##   [9] farver_2.1.2                rmarkdown_2.29
    ##  [11] GlobalOptions_0.1.2         vctrs_0.6.5
    ##  [13] Cairo_1.6-2                 memoise_2.0.1
    ##  [15] base64enc_0.1-3             htmltools_0.5.8.1
    ##  [17] S4Arrays_1.8.0              dynamicTreeCut_1.63-1
    ##  [19] SparseArray_1.8.0           Formula_1.2-5
    ##  [21] sass_0.4.10                 bslib_0.9.0
    ##  [23] htmlwidgets_1.6.4           plyr_1.8.9
    ##  [25] impute_1.82.0               cachem_1.1.0
    ##  [27] networkD3_0.4.1             igraph_2.1.4
    ##  [29] lifecycle_1.0.4             ggnetwork_0.5.13
    ##  [31] iterators_1.0.14            pkgconfig_2.0.3
    ##  [33] Matrix_1.7-3                R6_2.6.1
    ##  [35] fastmap_1.2.0               GenomeInfoDbData_1.2.14
    ##  [37] MatrixGenerics_1.20.0       clue_0.3-66
    ##  [39] digest_0.6.37               colorspace_2.1-1
    ##  [41] patchwork_1.3.0             AnnotationDbi_1.70.0
    ##  [43] S4Vectors_0.46.0            GENIE3_1.30.0
    ##  [45] Hmisc_5.2-3                 GenomicRanges_1.60.0
    ##  [47] RSQLite_2.3.9               labeling_0.4.3
    ##  [49] mgcv_1.9-3                  httr_1.4.7
    ##  [51] abind_1.4-8                 compiler_4.5.0
    ##  [53] withr_3.0.2                 bit64_4.6.0-1
    ##  [55] doParallel_1.0.17           htmlTable_2.4.3
    ##  [57] backports_1.5.0             BiocParallel_1.42.0
    ##  [59] DBI_1.2.3                   intergraph_2.0-4
    ##  [61] MASS_7.3-65                 DelayedArray_0.34.0
    ##  [63] rjson_0.2.23                tools_4.5.0
    ##  [65] foreign_0.8-90              nnet_7.3-20
    ##  [67] glue_1.8.0                  nlme_3.1-168
    ##  [69] grid_4.5.0                  checkmate_2.3.2
    ##  [71] cluster_2.1.8.1             reshape2_1.4.4
    ##  [73] generics_0.1.3              sva_3.56.0
    ##  [75] gtable_0.3.6                preprocessCore_1.70.0
    ##  [77] data.table_1.17.0           WGCNA_1.73
    ##  [79] XVector_0.48.0              BiocGenerics_0.54.0
    ##  [81] ggrepel_0.9.6               foreach_1.5.2
    ##  [83] pillar_1.10.2               stringr_1.5.1
    ##  [85] limma_3.64.0                genefilter_1.90.0
    ##  [87] circlize_0.4.16             splines_4.5.0
    ##  [89] dplyr_1.1.4                 lattice_0.22-7
    ##  [91] survival_3.8-3              bit_4.6.0
    ##  [93] annotate_1.86.0             tidyselect_1.2.1
    ##  [95] locfit_1.5-9.12             GO.db_3.21.0
    ##  [97] ComplexHeatmap_2.24.0       Biostrings_2.76.0
    ##  [99] knitr_1.50                  gridExtra_2.3
    ## [101] bookdown_0.43               IRanges_2.42.0
    ## [103] edgeR_4.6.0                 SummarizedExperiment_1.38.0
    ## [105] RhpcBLASctl_0.23-42         stats4_4.5.0
    ## [107] xfun_0.52                   Biobase_2.68.0
    ## [109] statmod_1.5.0               matrixStats_1.5.0
    ## [111] stringi_1.8.7               UCSC.utils_1.4.0
    ## [113] statnet.common_4.11.0       yaml_2.3.10
    ## [115] minet_3.66.0                evaluate_1.0.3
    ## [117] codetools_0.2-20            data.tree_1.1.0
    ## [119] tibble_3.2.1                BiocManager_1.30.25
    ## [121] cli_3.6.4                   rpart_4.1.24
    ## [123] xtable_1.8-4                munsell_0.5.1
    ## [125] jquerylib_0.1.4             network_1.19.0
    ## [127] Rcpp_1.0.14                 GenomeInfoDb_1.44.0
    ## [129] coda_0.19-4.1               png_0.1-8
    ## [131] fastcluster_1.2.6           XML_3.99-0.18
    ## [133] parallel_4.5.0              ggplot2_3.5.2
    ## [135] blob_1.2.4                  scales_1.3.0
    ## [137] crayon_1.5.3                GetoptLong_1.0.5
    ## [139] rlang_1.1.6                 KEGGREST_1.48.0

# References

Faith, Jeremiah J., Boris Hayete, Joshua T. Thaden, Ilaria Mogno, Jamey Wierzbowski, Guillaume Cottarel, Simon Kasif, James J. Collins, and Timothy S. Gardner. 2007. “Large-scale mapping and validation of Escherichia coli transcriptional regulation from a compendium of expression profiles.” PLoS Biology 5 (1): 0054–0066. https://doi.org/10.1371/journal.pbio.0050008.

Huynh-Thu, Vân Anh, Alexandre Irrthum, Louis Wehenkel, and Pierre Geurts. 2010. “Inferring regulatory networks from expression data using tree-based methods.” PLoS ONE 5 (9): 1–10. https://doi.org/10.1371/journal.pone.0012776.

Jin, J, F Tian, D C Yang, Y Q Meng, L Kong, J Luo, and G Gao. 2017. “PlantTFDB 4.0: toward a central hub for transcription factors and regulatory interactions in plants.” Nucleic Acids Res 45 (D1): D1040–D1045. https://doi.org/10.1093/nar/gkw982.

Marbach, Daniel, James C. Costello, Robert Küffner, Nicole M. Vega, Robert J. Prill, Diogo M. Camacho, Kyle R. Allison, et al. 2012. “Wisdom of crowds for robust gene network inference.” Nature Methods 9 (8): 796–804. https://doi.org/10.1038/nmeth.2016.

Margolin, Adam A., Ilya Nemenman, Katia Basso, Chris Wiggins, Gustavo Stolovitzky, Riccardo Dalla Favera, and Andrea Califano. 2006. “ARACNE: An algorithm for the reconstruction of gene regulatory networks in a mammalian cellular context.” BMC Bioinformatics 7 (SUPPL.1): 1–15. https://doi.org/10.1186/1471-2105-7-S1-S7.