BalanceVectors

Script: balancevectors.sh Package: var2 Class: BalanceVectors.java

Balances a labeled training-vector TSV (produced by VcfToTrainingVectors) into train/validation splits for neural-network training. Keeps all positives and performs stratified negative sampling so rare but difficult false positives are not drowned out by common easy ones. Sampling is spread across category axes — variant type crossed with depth, score, and event length — plus optional artifact axes (homopolymer run length, allele fraction, strand ratio, and mapping quality) where false positives concentrate. The remainder of the negative quota is filled with a representative random sample. All sampling and shuffling are deterministic given a seed.

Basic Usage

balancevectors.sh in=<vectors.tsv> outtrain=<file> outval=<file>

The input must be a tab-delimited vector file in the format produced by VcfToTrainingVectors, where the last column is a 0/1 label (1 = true variant, 0 = false positive). The tool writes two output files: a training split and a held-out validation split.

Sampling Strategy

Balancing proceeds in five steps, all deterministic given seed:

  1. Load and partition: All positives (label > 0.5) are kept in full. Negatives are separated for sampling.
  2. Target count: The number of negatives to select is chosen so that positives represent posfraction of the final output (default 30%).
  3. Enriched negatives: A per-category quota is drawn across existing axes (variant type × depth, score, event length; plus depth alone). If newcats=t, additional artifact axes (type × homopolymer run, allele fraction bins, strand ratio bins, mapping quality bins) are sampled at newweight times the base quota.
  4. Representative negatives: The remainder of the target is filled from a random sample of negatives not already selected by enrichment.
  5. Shuffle and split: Positives and chosen negatives are combined, globally shuffled, and split: the last valfraction of rows go to the validation file and the rest to training.

Memory Management

BalanceVectors loads all input vectors into memory at once. Budget approximately 1.5× the input file size in heap. The default JVM allocation is 4 GB; override with -Xmx for large inputs (tens of millions of vectors).

Parameters

I/O Parameters

in=<file>
Input labeled vector TSV. The last column must be a 0/1 floating-point label. Produced by VcfToTrainingVectors. Compressed input is supported.
outtrain=<file>
(train) Output training split. Receives the larger portion of the balanced and shuffled data. If valfraction=0 the entire balanced set is written here.
outval=<file>
(val, validate) Output validation split. Receives the last valfraction of the shuffled balanced set. Used for evaluating the trained model without data leakage.

Balancing Parameters

posfraction=0.3
(ratio) Target fraction of positives in the balanced output. 0.3 means 30% true variants and 70% negatives. Must be strictly between 0 and 1. The actual negative count is derived as pos_count × (1 − posfraction) / posfraction.
valfraction=0.1
Fraction of the final balanced set held out as the validation split. 0.1 means 10% goes to outval and 90% to outtrain. Must be in [0, 1).
enrich=t
When true, use stratified category sampling for negatives before filling the remainder randomly. When false, all negatives are drawn by simple random sampling with no category structure.
newcats=t
(artifactcats) When true, include the four artifact category axes — variant type × homopolymer run length, allele fraction bins, strand ratio bins, and mapping quality bins — in addition to the standard type/depth/score/event-length axes. These axes target regions where false positives concentrate. Sampled at newweight times the base per-category quota.
newweight=0.3
Fraction of the base per-category quota used when sampling the artifact axes (when newcats=t). A value of 0.3 means artifact-axis categories are sampled at 30% of the rate of existing categories, keeping them a minority of the enriched set rather than equal weight.
quota=
Override the automatically derived per-existing-category sample size. By default the quota is (targetNeg / 2) / numCategories. Setting this explicitly forces a fixed sample from each category bucket regardless of category count.
noscore=t
When true, the composite-score column (column index 29 in the VectorUMP45 33-feature layout) is replaced with 0 in both output files. This prevents the neural network from learning to copy the existing heuristic score rather than deriving its own features. Strongly recommended when training a new scoring model.
seed=42
Random seed for both the partial Fisher-Yates shuffles used during enriched category sampling and the full Fisher-Yates global shuffle before the train/val split. Given the same input and seed, the output is byte-for-byte reproducible.

Java Parameters

-Xmx
Set Java heap size, e.g. -Xmx64g. Large inputs (tens of millions of vectors) require enough heap to hold all lines simultaneously; budget approximately 1.5× the uncompressed file size. The default allocation is 4 GB.
-eoom
Exit on out-of-memory exception. Requires Java 8u92 or later. Recommended when running in automated pipelines so the process fails cleanly rather than hanging.
-da
Disable Java assertions. May improve throughput slightly in production, but assertions catch bugs during development and are left on by default.

Examples

Basic Balanced Split

# Balance a vector file and split into 90% train / 10% validation
balancevectors.sh in=variants.tsv outtrain=train.tsv outval=val.tsv

Uses all defaults: 30% positive target, 10% held out for validation, artifact category axes enabled, composite score zeroed, seed 42. Prints category counts, enriched negative count, representative fill count, and final positive fraction to stderr.

Higher Positive Fraction with Custom Seed

# 40% positives, 15% validation hold-out, reproducible with a different seed
balancevectors.sh in=variants.tsv outtrain=train.tsv outval=val.tsv \
    posfraction=0.4 valfraction=0.15 seed=1234

Use a higher posfraction when the dataset has very few positives and you want to reduce the training imbalance further. A different seed is useful for cross-validation experiments to verify that results are not seed-dependent.

Simple Random Sampling Without Artifact Axes

# Disable stratified enrichment entirely for a flat random negative sample
balancevectors.sh in=variants.tsv outtrain=train.tsv outval=val.tsv enrich=f

# Enrichment on but artifact axes off (use only type/depth/score/length axes)
balancevectors.sh in=variants.tsv outtrain=train.tsv outval=val.tsv newcats=f

enrich=f turns off all stratified sampling; negatives are drawn uniformly at random. newcats=f keeps the standard enrichment axes but drops the four artifact axes, which reduces the number of category buckets and raises the per-bucket quota. Both options are useful baselines for ablation studies.

Algorithm Details

Category Axes

BalanceVectors builds category keys from the VectorUMP45 33-feature layout. Each negative can appear in multiple buckets simultaneously; the enrichment pass deduplicates chosen indices so a single vector is never double-counted.

Existing axes (always used when enrich=t):

Artifact axes (used when newcats=t, sampled at newweight × base quota):

Sampling Procedure

Within each category bucket the tool applies a partial Fisher-Yates shuffle (Knuth) to draw up to quota indices uniformly without replacement. Because each negative index can appear in many buckets, a global chosen[] boolean array ensures that the total enriched set contains distinct vectors. The representative fill then draws uniformly from all unchosen negatives using another partial shuffle, pinning the final positive fraction to posfraction.

Score Column Zeroing

With noscore=t (default), column 29 (the CallVariants composite score) is replaced with the literal character 0 on output. The zeroing is done at the byte level during the write pass — no floating-point parsing — so the remainder of each line is reproduced exactly. This is the recommended setting when training a replacement scoring model: the network cannot shortcut learning by copying a preexisting signal.

Related Tools

Support

For questions and support: