4  Subnetwork Extraction

This chapter describes Step 3 of the FeatureMAP pipeline: extracting a robust metabolic subnetwork with extract_subnetwork() using the prize-collecting Steiner forest (PCSF) strategy.

Important

Prerequisites: You need a featuremap_result object from Feature Annotation, with stage "feature_annotated".

4.1 What extract_subnetwork() Does

extract_subnetwork() integrates the refined feature annotations from Step 2 with a metabolic reaction network (MRN) and applies repeated PCSF optimization to identify a robust subnetwork.

At a high level, this step does the following:

  1. Compute feature importance: Feature-level statistical evidence is summarized from condition and pvalue. Both are min–max rescaled and combined as importance = sqrt(score_fc * score_p), and the result is written back into res$feature_table.

  2. Build feature–metabolite mappings: The refined annotation table is projected onto MRN metabolite nodes, using HMDB.ID first and KEGG.ID as fallback, so that observed LC–MS features become terminal nodes attached to candidate metabolites.

  3. Run repeated PCSF optimization: PCSF is run times times with relative Gaussian perturbation of the edge costs, so that the result does not depend on a single optimization run.

  4. Aggregate robust network components: Node and edge frequencies are recorded across repeated runs, and the final subnetwork is constructed as the union of recurrent PCSF solutions.

  5. Refine annotation using network support: Feature–metabolite mappings are updated based on network evidence, producing anno_feature_table2.

This step moves the analysis from individual annotated features to a network-supported metabolite subnetwork, which is then used in downstream module extraction and interpretation.

4.2 Key Parameters

Parameter Default Description
res required featuremap_result returned by annotate_feature()
feature "all" Use all annotated features ("all") or only significant features ("sig")
pcutoff 0.05 Significance cutoff used when feature = "sig"
mrn NULL Optional custom metabolic reaction network (tidygraph::tbl_graph); automatically loaded if NULL
workers 4 Number of parallel workers
times 100 Number of repeated PCSF runs
b 20 Prize scaling factor in PCSF
mu 1e-4 Hub penalty coefficient; non-terminal nodes receive a negative prize proportional to their degree
w 25 Dummy edge cost in PCSF
r 0.20 Relative Gaussian edge-cost noise across repeated runs
grid_tune FALSE Whether to tune b and w over a parameter grid
b_grid seq(20, 40, by = 5) Candidate values of b when grid tuning is enabled
w_grid seq(20, 40, by = 5) Candidate values of w when grid tuning is enabled
times_tune 10 Number of repeated runs for each (b, w) combination during tuning
Note

The MRN is loaded automatically from the cached mrn resource when mrn = NULL, and is stored in res$mrn so that later steps reuse exactly the same network.

4.3 Basic Usage

# res is the output from Step 2 (annotate_feature)
res <- extract_subnetwork(
  res = res,
  feature = "all",
  mrn = NULL,
  workers = 4,
  times = 100,
  b = 20,
  mu = 1e-4,
  w = 25,
  r = 0.20,
  grid_tune = FALSE
)
Tip

Use feature = "all" when you want the network to see the full statistical landscape, and feature = "sig" together with pcutoff when you prefer to seed the network only with significantly changed features.

4.4 Optional: Grid Tuning for b and w

If you want data-driven parameter selection, enable grid tuning:

res <- extract_subnetwork(
  res = res,
  feature = "all",
  workers = 4,
  times = 100,
  grid_tune = TRUE,
  b_grid = seq(20, 40, by = 5),
  w_grid = seq(20, 40, by = 5),
  times_tune = 10
)

When grid_tune = TRUE, FeatureMAP records:

  • res$tuning_grid: full tuning results
  • res$tuning_best: selected best (b, w) and summary metrics

4.5 Result Interpretation

After successful extraction, first confirm that the subnetwork step completed successfully:

res$stage
# [1] "subnetwork_extracted"

names(res)
#  [1] "anno_feature_table2" "edge_frequency"      "node_frequency"
#  [4] "pcsf_subnet"         "mrn"                 "anno_redundancy"
#  [7] "anno_feature_table1" "refdata"             "feature_table"
# [10] "stage"               "object_type"         ".__enclos_env__"
# [13] "clone"               "initialize"

4.5.1 Extracted PCSF subnetwork

The extracted metabolic subnetwork is stored as an igraph object, where metabolite nodes are named by their InChI string and feature nodes by their variable_id:

res$pcsf_subnet
# IGRAPH ... UNWB 2217 4949 --
# + attr: name (v/c), prize (v/n), type (v/c), freq (e/n), weight (e/n)
# + edges from ... (vertex names):
# + ... omitted several edges

Node attribute type is "Terminal" for LC–MS feature nodes and "Steiner" for metabolite nodes; prize stores the node appearance frequency, and edge attributes freq / weight store how often each edge was recovered across the repeated runs. In res$node_frequency, the type column instead distinguishes "feature" from "metabolite" nodes.

4.5.2 Network-refined annotation table

After PCSF extraction, FeatureMAP updates the feature–metabolite annotation table by incorporating network evidence:

dim(res$anno_feature_table2)
head(res$anno_feature_table2[, c(
  "variable_id", "Compound.name", "HMDB.ID", "KEGG.ID",
  "edge_freq", "weighted_anno_score", "confidence_rank", "importance"
)])
# [1] 2909   34
#    variable_id           Compound.name     HMDB.ID KEGG.ID edge_freq weighted_anno_score
# 1 M105T384_POS           Peroxynitrite HMDB0002179  C16845      0.72               0.272
# 2 M105T384_POS 4-Hydroxymethylcatechol        <NA>  C14110      0.19               0.113
# 3 M105T384_POS 2,4,6-Trihydroxytoluene        <NA>  C16401      0.16               0.104
# 4 M105T384_POS   2-Hydroxybenzaldehyde HMDB0034170  C06202      0.15               0.101
# 5 M105T384_POS 2,4,5-Trihydroxytoluene        <NA>  C18317      0.14               0.098
# 6 M105T384_POS            Benzoic acid HMDB0001870  C00539      0.12               0.092
#   confidence_rank importance
# 1               1 0.06651944
# 2               2 0.06651944
# 3               3 0.06651944
# 4               4 0.06651944
# 5               5 0.06651944
# 6               6 0.06651944

anno_feature_table2 keeps all columns of anno_feature_table1 for the surviving rows, and adds:

Column Description
INCHI_ID InChI of the metabolite node in the MRN
edge_freq How often the feature–metabolite edge appeared across the repeated PCSF runs
weighted_anno_score Combination of score_norm and edge_freq, using an adaptive edge weight bounded between 0.1 and 0.3
confidence_rank Rank of the candidate within each feature, 1 being the most confident
importance Feature-level statistical importance carried over from res$feature_table

Compared with anno_feature_table1, this table incorporates network support from the extracted subnetwork. Metabolite candidates that are more consistently supported by the extracted metabolic network receive higher weighted_anno_score and better confidence_rank.

A quick way to see how much the network narrowed the candidate space:

length(unique(res$anno_feature_table1$variable_id))
length(unique(res$anno_feature_table2$variable_id))
# [1] 1106
# [1] 725

4.5.3 Other Result Components

  • res$feature_table: now contains score_fc, score_p and importance
  • res$mrn: the metabolic reaction network actually used
  • res$node_frequency: node appearance frequency across repeated runs
  • res$edge_frequency: edge appearance frequency across repeated runs
  • res$tuning_grid, res$tuning_best: available when grid tuning is used

4.6 Next Step

Once subnetwork extraction is complete, continue to Module Identification to detect connected functional modules from the extracted network.