Skip to content
Back to skills

Ai Science Zero Shot Mutation

ASecurity

Zero-Shot Mutation Effect Prediction with NumPy

  • 4 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 27, 2026
data-aipythonrusttestinggit

Works with

  • cli

Security analysis

A100/100

Scanned May 27, 2026

npx -y skills add Pavel-Kravchenko/Bioinformatics --skill ai-science-zero-shot-mutation --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Ai Science Zero Shot Mutation?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Ai Science Zero Shot Mutation
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/pavel-kravchenko-ai-science-zero-shot-mutation/badge)](https://www.skillsdirectory.com/skills/pavel-kravchenko-ai-science-zero-shot-mutation)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: ai-science-zero-shot-mutation
description: Zero-Shot Mutation Effect Prediction with NumPy
tool_type: python
primary_tool: NumPy
---

# Zero-Shot Mutation Effect Prediction

## Key Distinctions

- **Masked vs autoregressive**: ESM-1v uses MLM — mask position i, compare log-probs. Autoregressive models (ProtGPT2) compare full sequence log-likelihoods.
- **Single-site vs epistatic**: ESM-1v computes single-site marginals independently. For epistatic questions use ESM-IF1 or DMS-fine-tuned models.
- **ΔΔG vs ΔlogP**: ESM scores track evolutionary fitness, not thermodynamic stability — correlated but not identical.
- **Benchmark first**: check Spearman ρ on ProteinGym DMS assays for your protein family before trusting scores.

```python
import numpy as np
import pandas as pd

np.random.seed(13)
AA = list('ACDEFGHIKLMNPQRSTVWY')
```

## Core Formula

For a masked LM like ESM-1v, the zero-shot score for wt → mutant at position i:

$$\Delta_{i, \text{wt}\to\text{mut}} = \log P_\theta(\text{mut} \mid x_{\setminus i}) - \log P_\theta(\text{wt} \mid x_{\setminus i})$$

where $x_{\setminus i}$ is the sequence with position $i$ masked. Negative values mean the mutant is less likely under the model's evolutionary prior — a signal for deleterious effect.

ESM-1v trained on ~250M sequences: masking position i lets the model reconstruct it from residue covariance. Evolutionarily tolerated substitutions get high probability; disruptive ones get low.

## Real ESM-1v Usage (requires GPU + `fair-esm`)

```python
import esm
import torch
import torch.nn.functional as F

# Load ESM-1v (5 ensemble members available use model 1 as default)
model, alphabet = esm.pretrained.esm1v_t33_650M_UR90S_1()
batch_converter = alphabet.get_batch_converter()
model.eval()

def score_mutations(sequence: str, positions: list[int]) -> dict:
    \"\"\"
    Compute ESM-1v zero-shot ΔlogP for all mutations at given positions.
    positions: 1-indexed residue positions to score
    \"\"\"
    data = [("seq", sequence)]
    _, _, tokens = batch_converter(data)

    scores = {}
    with torch.no_grad():
        for pos in positions:  # pos is 1-indexed
            # Mask position i (tokens are 1-indexed due to <cls>)
            masked_tokens = tokens.clone()
            masked_tokens[0, pos] = alphabet.mask_idx  # pos+1 for <cls> offset

            logits = model(masked_tokens, repr_layers=[])["logits"]  # (1, L, vocab)
            log_probs = F.log_softmax(logits[0, pos], dim=-1)

            wt_aa = sequence[pos - 1]
            wt_idx = alphabet.get_idx(wt_aa)

            pos_scores = {}
            for mut_aa in "ACDEFGHIKLMNPQRSTVWY":
                mut_idx = alphabet.get_idx(mut_aa)
                delta = (log_probs[mut_idx] - log_probs[wt_idx]).item()
                pos_scores[f"{wt_aa}{pos}{mut_aa}"] = delta
            scores.update(pos_scores)
    return scores
```

## Ensemble Averaging

ESM-1v has 5 independently trained checkpoints. Averaging across all 5 significantly improves Spearman ρ with experimental fitness.

```python
# Load all 5 ESM-1v models
models_and_alphabets = [
    esm.pretrained.esm1v_t33_650M_UR90S_1(),
    esm.pretrained.esm1v_t33_650M_UR90S_2(),
    esm.pretrained.esm1v_t33_650M_UR90S_3(),
    esm.pretrained.esm1v_t33_650M_UR90S_4(),
    esm.pretrained.esm1v_t33_650M_UR90S_5(),
]
# Average the delta scores from all 5 models for each variant
```

## Toy Proxy (no GPU needed)

```python
HYDRO = set('AILMFWVY')
POLAR = set('STNQ')
CHARGED = set('KRHDE')

def aa_group(a):
    if a in HYDRO: return 'hydro'
    if a in POLAR: return 'polar'
    if a in CHARGED: return 'charged'
    return 'other'

def toy_zero_shot_delta(wt: str, mut: str) -> float:
    # penalize physicochemical group switches
    return 0.25 if aa_group(wt) == aa_group(mut) else -0.55
```

## Score All Single Substitutions

```python
wt_seq = 'MKTAYIAKQRQISFVKSHFSRQLEERLGLIEVQ'

records = []
for i, wt in enumerate(wt_seq):
    for mut in AA:
        if mut == wt:
            continue
        delta = toy_zero_shot_delta(wt, mut)
        records.append({'pos': i + 1, 'wt': wt, 'mut': mut, 'delta_ll': delta})

df = pd.DataFrame(records)
df.sort_values('delta_ll').head(8)
```

## Benchmark Against Pseudo-Fitness

```python
noise = np.random.normal(0, 0.08, size=len(df))
df['fitness'] = 0.6 + 0.5 * df['delta_ll'] + noise

corr = df[['delta_ll', 'fitness']].corr(method='spearman').iloc[0, 1]
print('Spearman correlation (delta vs fitness):', round(float(corr), 3))
```

## Clinical Triage Table

Combine zero-shot effect with rarity and structural confidence proxies.

```python
subset = df.sample(12, random_state=1).copy()
subset['rarity'] = np.random.uniform(0.2, 1.0, size=len(subset))
subset['plddt_proxy'] = np.random.uniform(55, 95, size=len(subset))

subset['priority'] = (
    0.5 * (-subset['delta_ll']) +
    0.3 * subset['rarity'] +
    0.2 * (subset['plddt_proxy'] / 100.0)
)

subset.sort_values('priority', ascending=False)[['pos', 'wt', 'mut', 'delta_ll', 'rarity', 'plddt_proxy', 'priority']]
```

## References

- [ESM repository (ESM-1v/ESM-2)](https://github.com/facebookresearch/esm)
- [ProteinGym benchmark](https://proteingym.org/)

## Pitfalls

- **Coordinate systems**: BED uses 0-based half-open; VCF/GFF use 1-based inclusive — mixing them causes off-by-one errors
- **Batch effects**: Always check for batch confounding before interpreting biological signal
- **Multiple testing**: Apply FDR correction (Benjamini-Hochberg) when testing thousands of features simultaneously

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.