agentsclimarketplace

Gene essentiality

Skill FridrichMethod/awesome-skills/skills/gene-essentiality

Performs in-silico single and double gene deletions, condition-dependent essentiality, and synthetic-lethality screens on genome-scale metabolic models with COBRApy, evaluating gene-protein-reaction rules and comparing FBA re-optimization against MOMA/ROOM minimal-adjustment. Use when predicting essential genes, finding synthetic-lethal pairs for drug targets, choosing a growth cutoff, deciding FBA vs MOMA vs ROOM for a knockout, making essentiality medium-specific to match an experiment, or validating predictions against Keio/Tn-seq/CRISPR screens with MCC.From its SKILL.md

Install
npx -y skills add FridrichMethod/awesome-skills --skill gene-essentiality

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 13 stars13 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

12.6 KB, ~3.1k tokens by cl100k_base, as published. Nobody here has run it

Version Compatibility

Reference examples tested with: COBRApy 0.29+, Python 3.10+

Before using code patterns, verify installed versions match. If versions differ:

  • Python: pip show <package> then help(module.function) to check signatures

If code throws ImportError, AttributeError, or TypeError, introspect the installed package and adapt the example to match the actual API rather than retrying.

Note: single_gene_deletion / double_gene_deletion spawn worker processes, so call them inside if __name__ == '__main__': (or pass processes=1) or a spawn platform will recurse. delete_model_genes is deprecated since 0.25; use knock_out_model_genes / remove_genes.

Gene Essentiality Analysis

"Which genes are essential for growth in my organism?" -> Delete each gene (via its GPR rule), re-solve the model, and call a gene essential when its knockout drops predicted growth below a chosen cutoff - always relative to a specific model and medium.

  • Python: cobra.flux_analysis.single_gene_deletion(), double_gene_deletion(), moma(), room() (COBRApy)

The governing principle: essentiality is a model-and-medium prediction, not a gene property

An in-silico knockout answers "can THIS network still make biomass on THIS medium after this perturbation?" Everything else follows from taking that literally:

  • A gene knockout is NOT a reaction knockout. Genes map to reactions through the gene-protein-reaction (GPR) rule: AND = protein complex (all subunits needed), OR = isozymes (any one suffices). A gene in an OR with a viable partner does nothing when deleted - isozyme masking is the dominant source of false non-essential calls and the reason synthetic lethals exist. Always delete GENES and let the GPR decide which reactions close; deleting reactions directly is a different, usually wrong, analysis.
  • The essential/non-essential CUTOFF is a policy choice, not a library default. COBRApy returns raw knockout growth rates; there is no growth_cutoff argument. The cutoff (commonly <1-10% of wild type) moves the essential set in the "sick but alive" tail. It should be reported and swept (1/2/5/10%); genes whose call flips are low-confidence hypotheses.
  • Essentiality is medium-dependent. Rich vs minimal media give different essential sets (a gene for a biosynthetic pathway is essential on minimal medium but dispensable when the product is supplied). To compare to an experiment, set the SAME medium the experiment used (LB vs M9), or the comparison is meaningless.
  • Predictions have a ceiling (~85-93% accuracy on E. coli metabolic genes). False essentials come from a missing bypass/isozyme in the model; false non-essentials come from biology FBA cannot see (regulation, toxicity, essential non-metabolic or structural roles). Report MCC, not accuracy - essential genes are the minority class, so accuracy is inflated by the true-negative pile.

Decision: which knockout method, which order

GoalMethodAssumption / when
Essential genes, evolved/adapted strain, or only hard lethalityFBA single_gene_deletionmutant re-optimizes to max growth; cheapest; lethality calls agree with MOMA anyway
Immediate/fresh transposon or CRISPR mutant (one growth cycle)MOMA momamutant stays closest in flux space to wild type (QP); fits fresh-mutant fluxes better
Fresh mutant where response is a few regulatory on/off switchesROOM roomminimizes the NUMBER of significantly changed fluxes (MILP); recovers short bypasses
Synthetic-lethal PAIRSdouble_gene_deletion on viable singlesboth single KOs viable, double lethal; O(n^2), restrict the gene list
Higher-order lethal sets (triples/quads)Fast-SL (flux-support pruning)brute-force O(n^3+) infeasible; Fast-SL prunes by flux support
Condition/medium contrastper-medium single_gene_deletion in with model:essentiality re-computed under each defined medium

MOMA/ROOM classify lethality similarly to FBA; they differ mainly on the quantitative growth of sick-but-alive mutants. Match the method to the timescale of the actual experiment.

Single-Gene Deletion Screen

Goal: Rank every gene by the growth defect of its knockout and flag essential and growth-reducing genes.

Approach: Take wild-type growth once, then single_gene_deletion clamps each gene's reactions to zero through the GPR, re-optimizes, and returns a DataFrame with columns ids (a set holding the deleted gene id(s)), growth, and status. The caller applies the cutoff.

import cobra
from cobra.flux_analysis import single_gene_deletion

model = cobra.io.load_model('textbook')
wt_growth = model.slim_optimize()

results = single_gene_deletion(model)          # DataFrame: ids (set of gene ids), growth, status
results['gene'] = results['ids'].apply(lambda s: list(s)[0])   # ids elements are gene-id STRINGS
results['relative'] = results['growth'] / wt_growth

ESSENTIAL_CUTOFF = 0.01                          # KO grows < 1% of WT -> essential (policy, not a default)
essential = results[results['relative'] < ESSENTIAL_CUTOFF]
print(f'Essential genes: {len(essential)} / {len(model.genes)} on this medium')

Classify with a threshold sweep (report low-confidence calls)

def classify_essentiality(results, wt_growth, cutoffs=(0.01, 0.02, 0.05, 0.10)):
    '''Classify genes and report how many calls flip across cutoffs (the sick-tail sensitivity).'''
    rel = results['growth'] / wt_growth
    calls = {c: set(results.loc[rel < c, 'gene']) for c in cutoffs}
    core = set.intersection(*calls.values())     # essential at every cutoff -> high confidence
    boundary = set.union(*calls.values()) - core # call depends on the cutoff -> low confidence
    return core, boundary

MOMA / ROOM: the immediate, non-re-optimized mutant

from cobra.flux_analysis import moma, room

# FBA assumes the mutant re-optimizes; a fresh knockout has not re-wired its regulation yet.
# MOMA keeps mutant flux closest (Euclidean) to wild type; ROOM minimizes the count of changed
# fluxes. Both need a wild-type reference solution and a QP/MILP-capable solver.
from cobra.util.solver import linear_reaction_coefficients
biomass = list(linear_reaction_coefficients(model))[0]   # the objective (biomass) reaction
wt = model.optimize()
with model:
    model.genes.get_by_id('b2276').knock_out()   # context-aware; reverts on block exit
    moma_sol = moma(model, solution=wt, linear=True)      # linear=True = fast LP approximation (lMOMA)
    # moma_sol.objective_value is the MINIMIZED ADJUSTMENT, not growth; read the biomass flux.
    print('MOMA mutant growth:', moma_sol.fluxes[biomass.id])

Synthetic Lethality (double deletions + epistasis)

Goal: Find gene PAIRS that are viable singly but lethal together - redundant pathways and isozymes, and candidate combination drug targets.

Approach: Restrict to genes whose single knockout is viable (a synthetic lethal requires both singles viable), run pairwise double_gene_deletion, and keep pairs whose double-KO growth falls below the cutoff. Cost is O(n^2), so subset the gene list. Score interactions against the multiplicative neutral expectation (independent effects on an exponential growth rate).

from cobra.flux_analysis import double_gene_deletion

viable = list(results.loc[results['relative'] > ESSENTIAL_CUTOFF, 'gene'])[:60]   # cap the O(n^2) sweep
dbl = double_gene_deletion(model, gene_list1=viable, gene_list2=viable)
dbl['n'] = dbl['ids'].apply(len)
sl_pairs = dbl[(dbl['n'] == 2) & (dbl['growth'] / wt_growth < ESSENTIAL_CUTOFF)]
print(f'Synthetic-lethal pairs: {len(sl_pairs)}')
# Genome-scale and higher-order (triple/quad) sets: use Fast-SL flux-support pruning (Pratapa 2015),
# not brute force.

Condition-Specific Essentiality (match the experiment's medium)

Goal: Compare essential-gene sets across defined media to separate core-essential genes from condition-specific ones.

Approach: Apply each medium inside a with model: block (so it reverts), run the deletion screen, and take intersections/differences of the essential sets. Define media with real functions, not lambdas (a lambda cannot contain an assignment).

def aerobic(m):
    m.reactions.EX_o2_e.lower_bound = -20

def anaerobic(m):
    m.reactions.EX_o2_e.lower_bound = 0

def essential_set(model, setup):
    with model:
        setup(model)
        wt = model.slim_optimize()
        res = single_gene_deletion(model)
        return set(res.loc[res['growth'] / wt < ESSENTIAL_CUTOFF, 'ids'].apply(lambda s: list(s)[0]))

sets = {name: essential_set(model, fn) for name, fn in [('aerobic', aerobic), ('anaerobic', anaerobic)]}
core = set.intersection(*sets.values())
condition_specific = {k: v - core for k, v in sets.items()}

Validate against experiment (MCC, matched medium)

# Compare predicted essentials to an experimental set (Keio single-KO, Tn-seq, or CRISPR fitness),
# on the SAME medium. Use MCC, not accuracy: essential genes are a minority class, so accuracy is
# inflated by the large true-negative pile.
from sklearn.metrics import matthews_corrcoef

def score(predicted_essential, experimental_essential, all_genes):
    y_pred = [g in predicted_essential for g in all_genes]
    y_true = [g in experimental_essential for g in all_genes]
    return matthews_corrcoef(y_true, y_pred)

Common Errors

SymptomCauseFix
Central gene predicted non-essentialit has an isozyme (OR in the GPR) that stays openexpected; that gene is a synthetic-lethal candidate, not truly dispensable
Deleting a reaction gives different results than deleting its genereaction KO ignores GPR; a gene may map to several reactions or share themdelete GENES (single_gene_deletion / gene.knock_out()), not reactions
TypeError: 'set' object ... .idids column holds sets of gene-id STRINGS, not gene objectslist(s)[0] gives the id string directly; no .id
Essential set disagrees with the papermedium mismatch (LB vs M9) or a different cutoffset the experiment's medium; report and sweep the cutoff
Script recurses / spawns endlesslydeletion functions parallelize; no __main__ guardwrap in if __name__ == '__main__': or pass processes=1
AttributeError: delete_model_genesdeprecated since cobra 0.25use knock_out_model_genes / remove_genes, or gene.knock_out()
High accuracy but poor agreement on real essentialsaccuracy inflated by true negatives (minority class)report MCC and sensitivity, not accuracy

Related Skills

  • systems-biology/flux-balance-analysis - The FBA/medium/objective foundation these knockouts rest on
  • systems-biology/model-curation - Missing isozymes/bypasses cause false essentials; curate before trusting calls
  • systems-biology/strain-design - Growth-coupling designs build on knockout logic
  • crispr-screens/hit-calling - Experimental essentiality screens to validate predictions
  • pathway-analysis/go-enrichment - Functional enrichment of predicted essential-gene sets

References

  • Orth JD, Thiele I, Palsson BO. 2010. What is flux balance analysis? Nat Biotechnol 28(3):245-248.
  • Segre D, Vitkup D, Church GM. 2002. Analysis of optimality in natural and perturbed metabolic networks. PNAS 99(23):15112-15117. (MOMA)
  • Shlomi T, Berkman O, Ruppin E. 2005. Regulatory on/off minimization of metabolic flux changes after genetic perturbations. PNAS 102(21):7695-7700. (ROOM)
  • Segre D, DeLuna A, Church GM, Kishony R. 2005. Modular epistasis in yeast metabolism. Nat Genet 37(1):77-83. (epistasis scoring, multiplicative expectation)
  • Pratapa A, Balachandran S, Raman K. 2015. Fast-SL: an efficient algorithm to identify synthetic lethal sets in metabolic networks. Bioinformatics 31(20):3299-3305.
  • Baba T, Ara T, Hasegawa M, et al. 2006. Construction of Escherichia coli K-12 in-frame, single-gene knockout mutants: the Keio collection. Mol Syst Biol 2:2006.0008.
  • Monk JM, Lloyd CJ, Brunk E, et al. 2017. iML1515, a knowledgebase that computes Escherichia coli traits. Nat Biotechnol 35(10):904-908.

What ships with it: 2 files

7.6 KB alongside SKILL.md, 1 of them executable

examples/

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.