You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 02-Enrichment.qmd
+2Lines changed: 2 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -54,4 +54,6 @@ GO and KEGG are the most frequently used for functional analysis. They are typic
54
54
55
55
Other gene sets include but are not limited to Disease Ontology ([DO](http://disease-ontology.org/)), Disease Gene Network ([DisGeNET](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4397996/)), [wikiPathways](https://www.wikipathways.org), Molecular Signatures Database ([MSigDb](http://software.broadinstitute.org/gsea/msigdb)).
56
56
57
+
In the current `clusterProfiler` ecosystem, classical ORA and GSEA are now complemented by enrichit-backed topology-aware and multi-omics workflows. The algorithm engine lives in `enrichit`, while `clusterProfiler` provides high-level interfaces such as `nseGO()`, `mnseGO()`, `nseKEGG()`, and `mnseKEGG()` for biological interpretation.
Functional enrichment analysis is a staple in bioinformatics for interpreting lists of genes identified from omics experiments. Behind the scenes of our ecosystem (`clusterProfiler`, `DOSE`, etc.), the heavy lifting is powered by the `enrichit` package.
@@ -10,6 +11,8 @@ We built `enrichit` with a clear philosophy: **minimal dependencies, maximum per
10
11
11
12
In this chapter, we will walk through the algorithmic backbone of enrichment analysis, moving from the standard ORA and GSEA to our newly introduced Network-based, multi-omics, and Weighted enrichment frameworks.
12
13
14
+
At the package architecture level, `enrichit` serves as the algorithm engine, while `clusterProfiler` provides the knowledge-base-aware high-level entry points. In practice, this means that topology-aware workflows are now available through wrappers such as `nseGO()`, `mnseGO()`, `nseKEGG()`, and `mnseKEGG()`, while multi-omics helpers such as `aggregate_omics()` and `aggregate_enrichment()` are also re-exported by `clusterProfiler` for downstream biological interpretation.
Over Representation Analysis (ORA) [@boyle2004] is a widely used approach to determine whether known biological functions or processes are over-represented (= enriched) in an experimentally-derived gene list, *e.g.* a list of differentially expressed genes (DEGs).
@@ -96,6 +99,7 @@ Our core philosophy is to leverage existing strengths seamlessly:
96
99
One RWR diffusion + one GSEA test. You get not only network-aware scores but also rigorous p-values and FDRs, with blazing speed.
97
100
98
101
```{r}
102
+
#| eval: false
99
103
library(clusterProfiler)
100
104
101
105
# 1. Fetch the full background PPI network for Human (taxID 9606)
@@ -118,6 +122,7 @@ Historically, RWR mathematically only accepts non-negative energy. This means yo
118
122
To solve this, `enrichit` introduces a dual-track propagation architecture (`mode = "signed"`). When you pass signed statistics (like `-log10(p) * sign(logFC)`), the algorithm automatically splits the input into up-regulated and down-regulated vectors. It runs two independent RWRs on the same network, and then subtracts the two diffused energy vectors to reconstruct a fully signed, network-aware score vector. This seamlessly bridges bidirectional network diffusion with dual-tail GSEA.
119
123
120
124
```{r}
125
+
#| eval: false
121
126
# Using signed statistics (e.g., -log10(p) * sign(logFC))
122
127
res_signed <- nsea(
123
128
geneList = signed_stats,
@@ -182,6 +187,45 @@ mnsea_res <- mnsea(
182
187
)
183
188
```
184
189
190
+
The same topology-aware engine can now be accessed from `clusterProfiler` using knowledge-base-aware wrappers. For example, the following high-level workflow reuses a single shared example object and performs GO- and KEGG-aware network enrichment without manually constructing the annotation backend.
191
+
192
+
```{r}
193
+
library(clusterProfiler)
194
+
library(org.Hs.eg.db)
195
+
196
+
demo <- clusterprofiler_enrichit_demo()
197
+
198
+
go_nse <- nseGO(
199
+
geneList = demo$geneList_evidence,
200
+
network = demo$network,
201
+
OrgDb = org.Hs.eg.db,
202
+
keyType = "ENTREZID",
203
+
ont = "BP",
204
+
minGSSize = 5,
205
+
maxGSSize = 500,
206
+
threshold = 1e-6,
207
+
maxIter = 50,
208
+
verbose = FALSE,
209
+
pvalueCutoff = 1,
210
+
method = "sample",
211
+
nPerm = 30
212
+
)
213
+
214
+
kegg_nse <- nseKEGG(
215
+
geneList = demo$geneList_evidence,
216
+
network = demo$network,
217
+
organism = demo$kegg_gson,
218
+
minGSSize = 5,
219
+
maxGSSize = 500,
220
+
threshold = 1e-6,
221
+
maxIter = 50,
222
+
verbose = FALSE,
223
+
pvalueCutoff = 1,
224
+
method = "sample",
225
+
nPerm = 30
226
+
)
227
+
```
228
+
185
229
### Explanation-ready Outputs for Multi-layer Results
186
230
187
231
Once you start doing topology-aware enrichment, the next question is obvious: *which layer actually drove the hit?* Instead of baking plotting logic into the engine, `enrichit` prepares explanation-ready tables that downstream packages such as `enrichplot` can consume directly.
@@ -230,6 +274,7 @@ By passing a `weight` vector (e.g., network centrality), the model calculates an
230
274
For GSEA, we seamlessly fuse your ranked statistics (like $\log FC$) with your external weights before passing them to the C++ engine. This amplifies the signals of core nodes while attenuating unreliable ones, without reinventing the wheel.
231
275
232
276
```{r}
277
+
#| eval: false
233
278
library(igraph)
234
279
235
280
# Fetch network as an igraph object to calculate topological weights
@@ -257,6 +302,7 @@ The beauty of weighted enrichment lies in its **infinite possibilities**. Your `
257
302
Finally, for ORA results, `enrichit` provides a Bayesian framework (`bayes_enrich()`) to estimate the posterior probability of explanatory terms. This helps to select the most likely active pathways while automatically penalizing redundancy among highly overlapping GO terms.
258
303
259
304
```{r}
305
+
#| eval: false
260
306
# After obtaining an ORA result object
261
307
bayes_res <- bayes_enrich(ora_result)
262
308
summary_res <- bayes_summary(bayes_res)
@@ -422,6 +468,8 @@ early_ora_res <- ora(
422
468
423
469
By decoupling ID mapping, statistical integration, and pathway enrichment, `enrichit` provides a clean, robust, and highly extensible pipeline for multi-omics functional analysis.
424
470
471
+
These workflow helpers are also available from `clusterProfiler`, which means the aggregated result can be sent directly to high-level functions such as `enrichGO()`, `gseGO()`, or `nseGO()` without changing the underlying multi-omics logic.
472
+
425
473
### 5. Late Fusion at the Pathway Level
426
474
427
475
Early fusion is elegant when your features align cleanly. But sometimes that assumption collapses immediately: transcriptomics might have a background of 20,000 genes, proteomics might only detect 4,000 proteins, and region-based omics may not even live in gene space before annotation. In these cases, forcing everything into one feature matrix is a great way to manufacture missing values and mapping noise.
@@ -465,6 +513,7 @@ After running a multi-omics integration, you may want to know whether a signific
465
513
First, you can classify the pattern of each pathway by comparing the merged results with single-omics results:
466
514
467
515
```{r}
516
+
#| eval: false
468
517
# Run ORA for individual omics
469
518
rna_ora_res <- ora(
470
519
gene = omics_gene_ids[rna_pvals < 0.05],
@@ -492,6 +541,7 @@ The `Omics_Pattern` column will label the pathway as `Shared`, `RNA-Specific`, `
492
541
Then, you can extract the gene-level contribution for a specific pathway to see the original statistics of the core enrichment genes:
493
542
494
543
```{r}
544
+
#| eval: false
495
545
# Get original multi-omics statistics for genes in the pathway
The format of input data, `geneList`, is documented in the @sec-id-convert. Beware that only gene sets with size in `[minGSSize, maxGSSize]` will be tested.
147
147
148
+
## Topology-aware GO enrichment
149
+
150
+
In classical GO enrichment, genes are treated as independent members of a gene set. When a biological network is available, `clusterProfiler` can now call the `enrichit` engine through the high-level wrappers `nseGO()` and `mnseGO()`. The former performs single-network enrichment, while the latter extends the same idea to a multi-layer setting.
151
+
152
+
To keep the example reproducible and consistent with the KEGG chapter, we reuse one shared demonstration object.
These wrappers preserve the familiar GO semantics (`OrgDb`, `ont`, and `keyType`) while delegating the network propagation and enrichment engine to `enrichit`.
205
+
148
206
149
207
150
-
## GO analysis for non-model organisms {#clusterprofiler-go-non-model}
151
208
152
209
Both the `enrichGO()` and `gseGO()` functions require an `OrgDb` object as the background annotation. For organisms that don't have `OrgDb` provided by `Bioconductor`, users can query one (if available) online via `r Biocpkg("AnnotationHub")`. If there is no `OrgDb` available, users can obtain GO annotation from other sources, e.g. from `r Biocpkg("biomaRt")`, or annotate the genes using [Blast2GO](https://www.blast2go.com/) or the [Trinotate](https://rnabio.org/module-07-trinotate/0007/02/01/Trinotate/) pipeline. Then the `enricher()` or `GSEA()` functions can be used to perform GO analysis for these organisms, similar to the examples using WikiPathways and MSigDB. Another solution is to create an `OrgDb` on your own using the `r Biocpkg("AnnotationForge")` package.
@@ -205,12 +206,15 @@ This ensures that the analysis runs offline and is fully reproducible using the
205
206
206
207
The `r Biocpkg("clusterProfiler")` package provides the `bitr_kegg()` function to support ID conversion via the KEGG API. This is particularly useful for species that do not have an `OrgDb` object but are supported by KEGG.
207
208
209
+
The examples in this section require live KEGG REST access. To keep the book build reproducible when the KEGG API is slow or unreachable, we show them without executing them during rendering.
210
+
208
211
### Basic Usage
209
212
210
213
Here is an example of converting KEGG IDs to NCBI Protein IDs and then to UniProt IDs for human genes.
211
214
212
215
```{r}
213
216
#| label: bitr-kegg
217
+
#| eval: false
214
218
library(clusterProfiler)
215
219
data(gcSample)
216
220
hg <- gcSample[[1]]
@@ -225,12 +229,13 @@ np2up <- bitr_kegg(eg2np[,2], fromType='ncbi-proteinid', toType='uniprot', organ
225
229
head(np2up)
226
230
```
227
231
228
-
The ID type (both `fromType` and `toType`) should be one of 'kegg', 'ncbi-geneid', 'ncbi-proteinid', or 'uniprot'. The 'kegg' ID is the primary ID used in the KEGG database. A rule of thumb is that 'kegg' ID corresponds to `entrezgene` ID for eukaryote species and `Locus` ID for prokaryotes.
232
+
The ID type (both `fromType` and `toType`) should be one of 'kegg', 'ko', 'ncbi-geneid', 'ncbi-proteinid', or 'uniprot'. The 'kegg' ID is the primary gene ID used in the KEGG database, while 'ko' refers to KEGG Orthology identifiers. A rule of thumb is that 'kegg' gene ID corresponds to `entrezgene` ID for eukaryote species and `Locus` ID for prokaryotes.
229
233
230
234
For many prokaryote species, `entrezgene` IDs are not available. For example, `ece:Z5100` (E. coli O157:H7 EDL933) has `NCBI-ProteinID` and `UniProt` links, but not `NCBI-GeneID`. Attempting to convert `Z5100` to `ncbi-geneid` will result in an error stating that `ncbi-geneid` is not supported. However, conversion to `ncbi-proteinid` or `uniprot` is possible.
@@ -242,13 +247,15 @@ A common confusion exists between `K` numbers (KEGG Orthology) and `ko` numbers
242
247
243
248
```{r}
244
249
#| label: bitr-kegg-path-ko
250
+
#| eval: false
245
251
bitr_kegg("K00844", "kegg", "Path", "ko")
246
252
```
247
253
248
254
To retrieve the names of the pathways (e.g., "Glutathione metabolism" instead of "ko00480"), we can define a simple helper function `ko2name` to query the KEGG API.
249
255
250
256
```{r}
251
257
#| label: ko2name-example
258
+
#| eval: false
252
259
x <- bitr_kegg("K00799", "kegg", "Path", "ko")
253
260
y <- ko2name(x$Path)
254
261
merge(x, y, by.x='Path', by.y='ko')
@@ -258,6 +265,7 @@ merge(x, y, by.x='Path', by.y='ko')
258
265
259
266
260
267
```{r}
268
+
#| eval: false
261
269
data(geneList, package="DOSE")
262
270
gene <- names(geneList)[abs(geneList) > 2]
263
271
@@ -274,6 +282,7 @@ Input ID type can be `kegg`, `ncbi-geneid`, `ncbi-proteinid` or `uniprot` (see a
274
282
For GO analysis, the `readable` parameter controls whether to translate the IDs to human-readable gene names. This parameter is not available for KEGG analysis. However, the `setReadable()` function can translate input gene IDs to gene names if the corresponding `OrgDb` object is available.
275
283
276
284
```{r}
285
+
#| eval: false
277
286
library(org.Hs.eg.db)
278
287
# 'kk' is the enrichKEGG result from the previous section
279
288
kk <- setReadable(kk, OrgDb = org.Hs.eg.db, keyType="ENTREZID")
@@ -283,6 +292,7 @@ head(kk)
283
292
## KEGG pathway gene set enrichment analysis {#clusterprofiler-kegg-pathway-gsea}
The same high-level design is now available for topology-aware KEGG analysis. `nseKEGG()` performs single-network enrichment and `mnseKEGG()` extends the workflow to multiple network layers, while keeping the familiar `clusterProfiler` interface.
307
+
308
+
For a lightweight and reproducible example, we reuse the same shared demo object as in the GO chapter and pass a local KEGG-style `GSON` object through the `organism` argument.
In a real analysis, users can pass a KEGG organism code such as `"hsa"` directly. Here we use a local `GSON` object to keep the example self-contained and reproducible.
355
+
294
356
## KEGG Pathway Classification
295
357
296
358
KEGG pathways are organized into a hierarchical structure with top-level categories such as "Metabolism", "Genetic Information Processing", "Environmental Information Processing", "Cellular Processes", "Organismal Systems", "Human Diseases", and "Drug Development". This classification helps users interpret enrichment results by providing higher-level biological context. For instance, users might be interested specifically in signaling pathways ("Environmental Information Processing") or metabolic pathways ("Metabolism") while excluding disease-related pathways.
@@ -310,6 +372,7 @@ To prevent this cached data from becoming outdated, the package utilizes **GitHu
0 commit comments