Skip to main content

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 with a 10 kb receptive field.

The model was trained on NCBI ~50,000 deduplicated viral genomes (as of Feb 2026). Trained model checkpoint and calibrator are bundled with the package and ready to run.

Install

From PyPI:

pip install prform

From bioconda (work in progress — recipe submitted, not yet on the channel; use pip until it lands):

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 by minus1_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

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()                      # loads bundled weights
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.

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.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for prform 0.2.1
File Size Uploaded Provenance Actions
prform-0.2.1.tar.gz 2.7 MB Without provenance Details for prform-0.2.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for prform 0.2.1
File Interpreter ABI Platform Actions
prform-0.2.1-py3-none-any.whl Python 3 none any Details for prform-0.2.1-py3-none-any.whl

Total release size: 5.5 MB

Release files / prform-0.2.1.tar.gz

Download URL prform-0.2.1.tar.gz
Size 2.7 MB
Tags Source
SHA-256 checksum
How to use checksums
a79ccbaff7290559576070a190bdc522117e4cc99a61340fc91e56a0e7164334
BLAKE2b-256 checksum
How to use checksums
c26b83ee10334c96dc86007f0cd78605b9104d33a57dd78beb66e7598d93f2d4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.13

Release files / prform-0.2.1-py3-none-any.whl

Download URL prform-0.2.1-py3-none-any.whl
Size 2.7 MB
Tags Python 3
SHA-256 checksum
How to use checksums
6b4106368625a8315bae5f24219f1b781972ccdadb72fd282182094b8bd791eb
BLAKE2b-256 checksum
How to use checksums
008f3abe3e274d2dbc6401ae3ad77bac973b0a5dce76884f0c3ecf578ac10b86
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.13

Security for prform 0.2.1

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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page