Skip to content

Commit 1076fb5

Browse files
committed
vampscore docs
1 parent fd6c28f commit 1076fb5

2 files changed

Lines changed: 83 additions & 0 deletions

File tree

doc/source/how-to/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ adaptive-inspect-run
3939
msm-simlist-custom-layout
4040
msm-filter-trajectories
4141
msm-drop-bad-trajectories
42+
msm-choose-features-vampscore
4243
msm-bootstrap-errors
4344
msm-interpret-its-plot
4445
msm-plot-fes
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# How to choose a featurization with a VAMP-2 score
2+
3+
## Goal
4+
5+
Decide *which* features to build your MSM on - and how many TICA dimensions and what TICA lag to keep - objectively rather than by intuition. The cross-validated VAMP-2 score ({py:func}`~htmd.projections.vamp.vampScore`) rates how much of the slow dynamics a featurization resolves; you score your candidates and keep the best one. This is the variational feature-selection idea of McGibbon and Pande.
6+
7+
## Minimal example
8+
9+
Starting from your `sims` (a {py:func}`~htmd.simlist.simlist`), score two candidate featurizations of the same trajectories and compare. Higher is better:
10+
11+
```python
12+
from htmd.ui import Metric, MetricSelfDistance, MetricDihedral, vampScore
13+
14+
# Candidate A: Ca-Ca contact map
15+
metrA = Metric(sims)
16+
metrA.set(MetricSelfDistance("protein and name CA", metric="contacts", periodic="chains"))
17+
dataA = metrA.project()
18+
dataA.fstep = 0.1
19+
20+
# Candidate B: backbone dihedrals
21+
metrB = Metric(sims)
22+
metrB.set(MetricDihedral())
23+
dataB = metrB.project()
24+
dataB.fstep = 0.1
25+
26+
for label, data in [("contacts", dataA), ("dihedrals", dataB)]:
27+
mean, std = vampScore(data, lag=2, dim=4, units="ns")
28+
print(f"{label}: VAMP-2 = {mean:.2f} +/- {std:.2f}")
29+
```
30+
31+
Keep the featurization with the highest cross-validated score.
32+
33+
## How to read the score
34+
35+
- **Higher is better** - a higher VAMP-2 score means the features resolve more of the slow dynamics.
36+
- **About 1.0 is the floor** - a featurization that captures no slow process (pure noise) scores around 1.0, the trivial stationary process.
37+
- **Compare like with like** - scores are only comparable when computed at the **same `lag` and `dim`**. Changing either changes the absolute score.
38+
- **It is cross-validated** - the score is averaged over `nfolds` folds, so a featurization that looks good only by overfitting the training data is penalised on the held-out folds. Use the mean and watch the spread (`std`).
39+
40+
## Common variations
41+
42+
Choose how many dimensions to keep. The score keeps rising as you add dimensions (it sums the squared singular values), so look for **diminishing returns** rather than a maximum:
43+
44+
```python
45+
for d in (2, 3, 4, 6, 8):
46+
mean, std = vampScore(data, lag=2, dim=d, units="ns")
47+
print(f"dim={d}: VAMP-2 = {mean:.2f} +/- {std:.2f}")
48+
```
49+
50+
Check robustness to the TICA lag:
51+
52+
```python
53+
for lag in (0.5, 1, 2, 5):
54+
mean, std = vampScore(data, lag=lag, dim=4, units="ns")
55+
print(f"lag={lag} ns: VAMP-2 = {mean:.2f} +/- {std:.2f}")
56+
```
57+
58+
Get the per-fold scores instead of the mean and standard deviation (for example to plot your own error bars):
59+
60+
```python
61+
scores = vampScore(data, lag=2, dim=4, units="ns", return_scores=True)
62+
```
63+
64+
If you have only a few long trajectories, cross-validating over whole trajectories is not possible; split each trajectory into blocks of `blocksize` frames instead:
65+
66+
```python
67+
mean, std = vampScore(data, lag=2, dim=4, units="ns", blocksize=1000)
68+
```
69+
70+
## Gotchas
71+
72+
- **Only compare at matched `lag` and `dim`.** A featurization scored at `dim=6` will out-score one at `dim=3` purely because of the extra dimensions, not because it is better.
73+
- **Do not simply maximise over `dim`.** Because VAMP-2 sums squared singular values, it rises monotonically with `dim`. Read the *shape* of the curve (where the gains flatten), not the peak.
74+
- **A tie is a real and useful answer.** Featurizations that both capture the slow process well score about the same - the score is telling you the choice does not matter for the kinetics, so decide on other grounds such as clustering robustness or cost. For example, on the villin headpiece a Cα contact map and raw Cα distances score about equally; the contact map is preferred there for its clustering robustness, not because it resolves more dynamics.
75+
- **Needs at least 2 trajectories** for the default whole-trajectory cross-validation. With a single long trajectory, pass `blocksize` so it can be split into independent blocks.
76+
- **Scoring is not validation.** A high VAMP-2 score says the features are promising; it does not replace building the MSM and checking the implied timescales and the Chapman-Kolmogorov test.
77+
78+
## See also
79+
80+
- {py:func}`htmd.projections.vamp.vampScore` - the API reference.
81+
- {doc}`How to read an implied-timescales plot <msm-interpret-its-plot>` - the validation step after picking features.
82+
- {doc}`Protein folding MSM <../tutorials/analysis/villin-folding>` and {doc}`Ligand binding MSM <../tutorials/analysis/trypsin-benzamidine-binding>` - the full pipelines these features feed into.

0 commit comments

Comments
 (0)