PRForm
Predict programmed ribosomal frameshift (PRF) sites in Viral genomes.
prform is a deep-learning tool that scores every nucleotide in viral genome
sequence for the probability that a -1 or +1 frameshift event occurs there.
Predictions come from a 1D residual network; two trained models are bundled
and selectable with --model (see Choosing a model).
The models were trained on NCBI ~50,000 deduplicated viral genomes (as of Feb 2026). Trained model checkpoints and calibrators are bundled with the package and ready to run.
Install
From PyPI:
pip install prform
From bioconda:
conda install -c conda-forge -c bioconda prform
From source (development):
git clone https://github.com/khoa-yelo/PRForm.git
cd PRForm/prform_pkg
pip install -e .[dev]
Usage
prform predict input.fasta --outdir results/
(equivalent: python -m prform predict ... — useful when ~/.local/bin
isn't on your PATH.)
Writes two files into results/:
predictions.csv— one row per FASTA record: the top-k predicted peak positions, each with its calibrated -1 and +1 probabilities and the predicted frameshift type (-1 PRF, +1 PRF, or no frameshift detected). Peaks are ranked byminus1_PRF_prob + plus1_PRF_prob.predictions.h5— full per-nucleotide calibrated probability tracks.
predictions.h5 layout:
records/
accession_id (R,) str
length (R,) int
top{k}_pos (R,) int # k = 1..top_k, 1-based; -1 if no peak
top{k}_minus1_PRF_prob (R,) float32 # the track values at that position
top{k}_plus1_PRF_prob (R,) float32
top{k}_type (R,) int8 # -1 PRF, +1 PRF, or 0 = none
per_nucleotide/
{accession_id}/ # one group per FASTA record
no_PRF_prob (L,) float32
minus1_PRF_prob (L,) float32
plus1_PRF_prob (L,) float32
With --both-strands each orientation gets its own block — fwd_/rev_
column and dataset prefixes, and fwd/rev per-nucleotide subgroups — see
Scoring both strands.
Read a record's per-nucleotide tracks in Python:
import h5py
with h5py.File("results/predictions.h5") as f:
for acc in f["records/accession_id"].asstr()[:]:
g = f[f"per_nucleotide/{acc}"]
minus1 = g["minus1_PRF_prob"][:]
plus1 = g["plus1_PRF_prob"][:]
prf_track = minus1 + plus1
Choosing a model
Two trained models ship with the package. Both were trained on the same data with the same scheme and differ only in how much sequence context each position sees:
--model |
context | receptive field | parameters | notes |
|---|---|---|---|---|
10k (default) |
+/-5000 nt | 10001 | 696,739 | the original model |
2k |
+/-1000 nt | 2001 | 359,043 | half the size, narrower context |
prform predict input.fasta --outdir results/ --model 2k
Input and output are identical for both models — same CSV columns, same
HDF5 layout, same per-nucleotide track shapes — so you can swap --model
without touching anything downstream. Only the probabilities change.
Each model ships with the calibrator that was fit on its own predictions, and
--model selects both together. Calibration is specific to a checkpoint's
probability scale, so only override --calibrator alongside --checkpoint.
On held-out validation data the two are close: the 10k model is marginally
better at ranking (sequence-level PR-AUC 0.892 vs 0.884) while 2k reaches
comparable peak localisation at half the parameters. 10k remains the
default; 2k is worth trying when context beyond ~1 kb is unlikely to help.
Scoring both strands
PRForm is a directional detector: it only sees a frameshift in the
orientation it is given. A PRF encoded on the minus strand of your input is
invisible on a forward-only pass. Pass --both-strands to score each record in
both orientations:
prform predict genomes.fasta --outdir results/ --both-strands
Both orientations are reported. The peaks and tracks are duplicated into a forward block and a reverse block:
predictions.csv
accession_id, length,
fwd_top{k}_pos, fwd_top{k}_minus1_PRF_prob, fwd_top{k}_plus1_PRF_prob, fwd_top{k}_type,
rev_top{k}_pos, rev_top{k}_minus1_PRF_prob, rev_top{k}_plus1_PRF_prob, rev_top{k}_type
predictions.h5
records/ # same fwd_/rev_ prefixes as the CSV
accession_id, length,
fwd_top{k}_{pos,minus1_PRF_prob,plus1_PRF_prob,type}
rev_top{k}_{pos,minus1_PRF_prob,plus1_PRF_prob,type}
per_nucleotide/
{accession_id}/
fwd/ no_PRF_prob, minus1_PRF_prob, plus1_PRF_prob (L,) each
rev/ no_PRF_prob, minus1_PRF_prob, plus1_PRF_prob (L,) each
The reverse block is mirrored back into forward-genome coordinates, so both
blocks index the same nucleotide: fwd_top1_pos, rev_top1_pos and index i
of either track all refer to position i+1 of the sequence as you supplied it.
Class channels are not swapped — a -1 PRF read on the reverse complement
stays in minus1_PRF_prob, because the shift direction is defined relative to
the strand being read.
Test the install
prform ships with small FASTA fixtures (one folder per labeled
frameshift class) so you can verify the install end-to-end without any
external data. Copy them into your working directory:
prform download-examples ./prform_examples
Layout after download:
prform_examples/
plus1_PRF/ influenza_pax.fasta
minus1_PRF/ coronavirus_khosta2.fasta, phage_tyson.fasta
no_PRF/ monkeypox, ledantevirus, nanovirus, ourmiavirus, orbivirus
Run predict on each class:
# +1 PRF: peak should land near the labeled site
prform predict prform_examples/plus1_PRF/influenza_pax.fasta \
--outdir prform_test/plus1
# -1 PRF: peak should land near the labeled site
prform predict prform_examples/minus1_PRF/coronavirus_khosta2.fasta \
--outdir prform_test/minus1
# no PRF: no frameshift should be called
prform predict prform_examples/no_PRF/nanovirus.fasta \
--outdir prform_test/no_prf
cat prform_test/plus1/predictions.csv
cat prform_test/minus1/predictions.csv
cat prform_test/no_prf/predictions.csv
Expected behavior:
| fixture | labeled site | what to look for |
|---|---|---|
plus1_PRF/influenza_pax.fasta |
+1 PRF @ pos 582 | top1_pos within a few nt of 582, top1_type == 1 |
minus1_PRF/coronavirus_khosta2.fasta |
-1 PRF @ pos 13248 | top1_pos near 13248, top1_type == -1 |
minus1_PRF/phage_tyson.fasta |
-1 PRF @ pos 10279 | top1_pos near 10279, top1_type == -1 |
no_PRF/*.fasta |
none | top1_type == 0 (no frameshift called) |
Each labeled-positive FASTA header carries the labeled site for easy comparison.
Python API
from prform import PRFormPredictor
predictor = PRFormPredictor() # default bundled model (10k)
predictor = PRFormPredictor(model="2k") # narrow-context model
results = predictor.predict_fasta("input.fasta") # list of dicts
# or
results = predictor.predict_sequences([("rec1", "ACGT" * 1000)])
# score both orientations, keep the better strand per record
results = predictor.predict_fasta("input.fasta", both_strands=True)
Each result entry is:
| key | type | meaning |
|---|---|---|
accession_id |
str | FASTA record id |
length |
int | sequence length in nt |
strand |
str | +, or - when the reverse complement scored higher |
no_PRF_prob |
(L,) float32 | calibrated per-nucleotide class |
minus1_PRF_prob |
(L,) float32 | probabilities; the three sum |
plus1_PRF_prob |
(L,) float32 | to 1 at each position |
top |
list | per peak: {pos, minus1_PRF_prob, plus1_PRF_prob, type}, pos 1-based |
fwd, rev |
dict or None | each orientation's own tracks + top |
Track names match predictions.h5, and everything is in forward-genome
coordinates. fwd/rev are populated only with both_strands=True.
The result schema does not depend on which model is selected. To list the bundled models programmatically:
from prform import available_models
available_models()
# {'10k': '10001 nt context (+/-5000)',
# '2k': '2001 nt context (+/-1000), half the parameters'}
Hardware
CPU works. GPU is faster — prform automatically uses CUDA when available.
For long sequences (>1 Mb total input) a GPU is recommended.
License
MIT
Metadata
Release files for prform 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| prform-0.3.0.tar.gz | 4.1 MB | Without provenance | Details for prform-0.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| prform-0.3.0-py3-none-any.whl | Python 3 | none | any | Details for prform-0.3.0-py3-none-any.whl |
Total release size: 8.2 MB
Release files / prform-0.3.0.tar.gz
| Download URL | prform-0.3.0.tar.gz |
|---|---|
| Size | 4.1 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
428a834419f136ad0d9ff8d0bdc202c21b168debbf2fef488ab41849ca6b0f29
|
|
BLAKE2b-256 checksum How to use checksums |
8d55cd6767f8f6d2c66e5b9f06a934b4e3b7ec283bb548b3a778ddecb2a02cf0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|
Release files / prform-0.3.0-py3-none-any.whl
| Download URL | prform-0.3.0-py3-none-any.whl |
|---|---|
| Size | 4.1 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5d642a4f61d3cefe6683ee80963e2c40288a228c3efc10b3c443f6553ba61905
|
|
BLAKE2b-256 checksum How to use checksums |
ce191165bc79ee932cf820711e9b4caef38000880f6bad09a03b6071588d533f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|
Security for prform 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.