Alignment-free QC benchmark: snipe
How closely snipe's sketch-based QC estimates match alignment ground truth, scored per sequencing workload and per k-mer configuration on the dog genome. Whole-genome assays, exome capture, and RNA are each scored separately.
What we tested, and why
Sequencing quality control normally means aligning reads to a reference and reading depth, coverage, error and mapping statistics off the alignment. By contrast, snipe skips that step: it builds a FracMinHash k-mer sketch of the raw reads, compares it to a sketch of the reference, and estimates the same quantities directly. Whether that shortcut is trustworthy is an empirical question, and this benchmark addresses it directly. We simulated reads for which the truth is known exactly, ran both a sketch-based and an alignment-based pass over the same reads, and measured how closely the two agree.
The appeal of the alignment-free route is practical. Aligning deep libraries is slow and reference-heavy, and QC is often the one step you want before committing to that cost. If a compact sketch can reproduce the alignment's verdict, QC becomes something you can run directly on the raw reads, with no alignment step. But QC is only useful if it is right, and a sketch discards most of the data by construction, so the estimates have to be validated against the alignment they are meant to replace, across the range of conditions a real library might present.
We built that range on the dog genome, Canis familiaris CanFam3.1. Reads were simulated across a grid of
two independent perturbations: sequencing error, the noise a sequencer adds to otherwise-correct
reads, and mutation, real differences between the sampled genome and the reference. Both were
swept from zero to 5%, from an exact reference_match control to heavily
diverged libraries, so the grid spans both the easy cases and the divergence where a sketch should fail.
Five assay types
A whole-genome library and an exome capture fail in different ways, so we simulated five assay types, not one.
-
Whole-genome shotgun 43 librarieswgsim, 150 bp paired-end, depths 0.5×, 1×, 5×, 30×Tests QC from barely-there to comfortable coverage.
-
Whole-genome with indels 33 librarieswgsim, held at 5×, indels raised to 15%, 30%, 45% of all mutationsA targeted stress test of the metric most sensitive to gaps.
-
Whole-exome capture 33 librariesNEAT, depths 10×, 40×, 80×Reads concentrate on a small target, so depth and breadth are scored on the captured regions rather than genome-wide, and it is scored on its own.
-
Metagenomic 11 libraries5× dog reads plus a fixed block of real off-reference reads (
SRR8073716); only 45.8% on-referenceA direct test of whether the sketch recovers the true on-reference fraction. -
RNA 30 librariesPolyester, 5–25M reads against a 61,007-transcript reference; scored on its ownA short, isoform-redundant transcriptome behaves unlike any genomic library, so mixing it in would only blur both.
Every library is defined by the same error × mutation grid below, crossed with that assay's own depth, indel, or read-count axis.
Against each library we run the two arms on identical reads. On one arm, snipe sketches the reads and estimates QC without
ever aligning them; in parallel, bwa mem → samtools → Qualimap, with a custom CIGAR/MD
parser, produce the alignment-based truth. Sequence change is counted as events (one SNP is one, a 20 bp
indel is one) to match what the sketch actually measures; mapping rate is taken read-level (mapped reads over
total, which unlike the base-level rate is not blind to unmapped reads); and for the exome, depth and breadth are
measured on-target. What the tables and figures below report is simply how far snipe's estimate sits from that
truth, summarised as a single score, across every assay and every k-mer setting.
The error × mutation grid ▸
The eleven conditions every genomic assay is swept across (RNA uses a ten-condition variant). Sequencing error is added by the read simulator; mutation is introduced into the reference before reads are drawn.
| condition | sequencing error | mutation |
|---|---|---|
| reference_match | 0 | 0 |
| no_error_low_variance | 0 | 0.1% |
| no_error_med_variance | 0 | 1% |
| no_error_hi_variance | 0 | 5% |
| low_error_no_variance | 0.1% | 0 |
| low_error_low_variance | 0.1% | 0.1% |
| med_error_no_variance | 1% | 0 |
| med_error_med_variance | 1% | 1% |
| hi_error_no_variance | 5% | 0 |
| hi_error_low_variance | 5% | 0.1% |
| hi_error_med_variance | 5% | 1% |
Software, commands & parameters ▸
Every command below is templated from the workflow; ⟨angle-bracket⟩ terms are the values swept
across libraries. Reads are 150 bp paired-end throughout; genomic fragments are 350 ± 50 bp, RNA fragments
200 ± 25 bp. The reference is Canis familiaris CanFam3.1 (GCF_000002285.3).
These three assays are the same wgsim command; they differ only in the depth, the indel sweep,
and, for metagenomic, a spike-in appended afterwards. Sequencing error and mutation are each swept over
0 / 0.001 / 0.01 / 0.05 in all three.
wgsim -h \ # haploid -N ⟨n_reads⟩ -1 150 -2 150 \ # paired 150 bp -d 350 -s 50 \ # fragment 350 ± 50 bp -e ⟨error⟩ -r ⟨mutation⟩ \ # swept 0 / 0.001 / 0.01 / 0.05 -R ⟨indel_frac⟩ -X ⟨indel_ext⟩ \ # see per-assay settings below -S ⟨seed⟩ CanFam3.1.fa r1.fq r2.fq seqkit fq2fa r1.fq > r1.fa # reads are sketched as FASTA
| assay | depth (-N) | indels (-R / -X) | then | libraries |
|---|---|---|---|---|
| WGS | 0.5×, 1×, 5×, 30× | 0.15 / 0.3 (fixed) | none | 43 |
| WGS+indels | 5× | 0.15/0.30/0.45, 0.3/0.6/0.9 | none | 33 |
| metagenomic | 5× | 0.15 / 0.3 (fixed) | + spike-in ↓ | 11 |
Metagenomic only: append a fixed block of real, off-reference metagenome reads
(SRR8073716), leaving 45.8% of reads on-reference.
cat 50M_SRR8073716_1.fa >> r1.fa # real off-reference spike-in cat 50M_SRR8073716_2.fa >> r2.fa
On-target exome sequence is extracted per chromosome so NEAT sees only capture regions; coverage then equals on-target depth (10× / 40× / 80×). The golden VCF gives the true variant count.
bedtools getfasta -fi CanFam3.1.fa -bed ⟨chrom⟩_exome.bed -fo exome.fa neat read-simulator -c config.yml -o out -p n # config.yml: read_len 150, coverage ⟨10/40/80⟩, ploidy 1, paired_ended true # fragment_mean 350, fragment_st_dev 50 # avg_seq_error ⟨error⟩, mutation_rate ⟨mutation⟩, rng_seed ⟨seed⟩
Mutations are introduced as SNP substitutions (length-preserving, no indels), the transcriptome (61,007 transcripts) is extracted from the mutated genome, and Polyester draws reads with uniform fragmentation (no positional bias).
python mutate_genome.py --input CanFam3.1.fa \ --rate ⟨mutation⟩ --output mutated.fa # SNP substitutions only # → extract 61,007-transcript transcriptome from the mutated genome Rscript simulate_polyester.R --transcriptome txome.fa \ --num-reads ⟨5M/15M/25M⟩ --error-rate ⟨error⟩ \ --read-length 150 --frag-mean 200 --frag-sd 25 # Polyester, bias=none, paired
The same reads are aligned and profiled. Qualimap gives depth, breadth and mapping; a custom parser counts sequence change as events (one SNP = 1, a 20 bp indel = 1) to match what the sketch measures.
bwa index CanFam3.1.fa bwa mem -t N CanFam3.1.fa r1.fa r2.fa | samtools view -bS - > aln.bam samtools sort -o aln.sorted.bam aln.bam && samtools index aln.sorted.bam qualimap bamqc -bam aln.sorted.bam -outdir qc -nt N --java-mem-size=24G python bamqc_final.py aln.sorted.bam # event-based sequence-change truth
Each library is sketched and QC'd against a reference sketch. For the exome, the merged capture regions
are passed as --amplicon so depth and breadth are reported on-target.
snipe sketch --sample reads.fa -o reads.sig \ --k1-size ⟨k1⟩ --k2-size ⟨k2⟩ --scale ⟨scale⟩ --name ⟨id⟩ snipe qc --samples-list siglist.txt \ --reference genome.sig --amplicon exome.sig \ # --amplicon = exome ROI (drives the WXS on-target metrics) -o qc.tsv -v --advanced --hidden
The full k-mer sweep behind these pages, 231 configurations per library:
| k1 (core) | 21, 25, 31, 35, 41, 45, 51, 55, 61, 65, 71 (11 values) |
| k2 (edge) | k1 + {2, 4, 6, 8, 10, 14, 18} (7 extensions) |
| scale | 1,000 / 10,000 / 100,000 (FracMinHash) |
| snipe v2.1.0 | alignment-free QC (FracMinHash sketch + qc) |
| wgsim | whole-genome, indel & metagenomic reads |
| NEAT | whole-exome capture reads |
| Polyester (R) | RNA-seq reads |
| bwa, samtools, Qualimap | alignment ground truth |
| seqkit, bedtools | read/format and region handling |
The snipe version is verified as v2.1.0; other tool versions are pinned in the project conda environments.
How a single score is built
Each cell in the tables below is one number in [0,1] that summarises how closely
snipe's estimate matches the alignment, blended across the four QC metrics and aggregated across the assays in a
workload. Expand for the exact formula.
The full definition ▸
Every value below is in [0,1], higher is better, and is the best achievable score for the
current filters, shown with the k-mer configuration that achieves it.
Four QC metrics
Sequence-change rate, mean depth, mapping rate, coverage breadth. (The manuscript states why these metrics were selected; here they are all shown.) snipe's estimate for each is compared to the alignment ground truth (Qualimap / bamqc; read-level mapping rate; event-based sequence-change rate).
Per-metric accuracy (hybrid)
Each metric's accuracy combines two things equally:
accuracy = ½ × [ (1 − min(MdAPE, 1)) + max(0, r) ]
Closeness is 1 − min(MdAPE, 1), where MdAPE is the median across a dataset's
libraries of the relative error |estimate − truth| / truth (median absolute percentage error, the median rather than the usual mean;
a 5% typical error gives closeness 0.95). Agreement is max(0, r), the Pearson
correlation between snipe's estimates and the truth across libraries, clamped at 0. The two are averaged
50 / 50. The agreement term is only included where the ground truth actually varies (so a correlation is
meaningful); where the truth is near-constant, accuracy is closeness alone.
Aggregation
Per assay: the four metric accuracies are combined into two flavors, a plain average (equal) and one that weights sequence-change ×2 (the metric the alignment truth pins down most directly). Per workload: the geometric mean across the assays in the bundle, so a single weak assay pulls the bundle down harder than a plain average would.
Two k-modes
Fixed restricts to k1 ∈ {21, 31, 51} (the manuscript's operating points).
Free covers the entire sweep (k1 ∈ {21…71}, all edge extensions, all scales) and reports the best score.
Why WXS and RNA are separate
Exome capture (WXS) and RNA are targeted or transcriptome assays with a small effective reference, so both do best at small k1 (RNA strongly so, WXS only mildly), whereas the whole-genome assays (WGS, indels, metagenomic) favour large k1. They are scored on their own: WXS because its depth and breadth are measured on-target rather than genome-wide, RNA because it maps to a separate transcriptome; bundling either into the large-k1 whole-genome group would average opposite behaviors together.
Scores by workload & configuration
Genomic workloads
the 3 whole-genome datasets and every combination of themEach row is a workload: one dataset, or a bundle of several. A bundle's score is the geometric mean across its datasets; it answers “how well does snipe do overall if I run these assay types?”, and it is not a mixed sample. 1.00 = snipe reproduces the alignment result exactly. Hover a label to see the dataset; click ▸ to see every k-mer setting.
Exome capture (WXS), scored independently
targeted assay, small effective referenceWXS is not mixed with the whole-genome assays. Its reads cover only the captured exome, so depth and breadth are scored on-target, and its small effective reference makes it favour small k1, like RNA.
RNA, scored independently
transcriptome, k-sensitiveRNA is not mixed with the genomic assays. Its accuracy peaks at small k1 and degrades as k1 grows (edge-mer saturation on the short transcriptome reference).
Decision explorer
how the score moves across configurationsDoes the k-mer setting matter for my data? A flat curve means snipe is insensitive to the choice; a falling curve means the setting matters and small k-mers are better.
Score vs core k-mer size
Score heatmap
Every workload at the chosen config
Findings & conclusions ▸
What the benchmark shows. On the Canis familiaris CanFam3.1 reference, across simulated sequencing workloads, snipe's alignment-free QC estimates reproduce alignment-derived ground truth closely, with best-achievable composite accuracy above 0.96 for the whole-genome workloads and for exome capture, and about 0.90 for RNA, the hardest case. These are the best scores over the k-mer sweep; a single compromise configuration stays within 0.02 of each workload's own best, RNA excepted (below).
Genomic QC is recovered without alignment
For whole-genome (150 bp), indel-enriched and metagenomically-contaminated reads, composite scores sit near 0.98 (WGS 0.98, indels 0.99, metagenomic 0.98). Sequence-change rate is the strongest signal: snipe's estimate matches the event-based alignment truth at r ≥ 0.999 for all three. Where a metric carries genuine dynamic range (sequence-change, and depth in coverage-varying designs), snipe tracks it closely; where the truth is saturated by construction (mapping and breadth for fully on-reference reads) the estimates agree in value even though a correlation there is uninformative. Because those two metrics are near 1 by construction for on-reference reads, they contribute high closeness almost automatically; the sequence-change-weighted score is the more stringent test of snipe's skill.
Exome capture is close behind, as a targeted assay
Whole-exome capture (WXS) is scored on its own because it is a targeted assay: reads cover only the captured regions, so depth and breadth are measured on-target rather than genome-wide. Its best composite accuracy is about 0.97, close to the whole-genome workloads, but it peaks at small k1 (best at k1 = 21) rather than large, because only a small fraction of the genome is on-target and the informative sketch is correspondingly small. Sequence change is recovered well (r ≈ 0.97 at k1 = 21, falling to 0.90 by k1 = 51), while mapping and breadth saturate near 1.0, as expected for reads that are almost entirely on-target.
Mapping rate reflects on-reference content in mixed samples
The metagenomic workload is dog whole-genome reads spiked with a fixed block of off-reference reads; mapping such a sample to the dog reference recovers only its on-reference fraction. Measured against the appropriate read-level ground truth (mapped reads / total), snipe's alignment-free mapping estimate agrees closely (0.46 versus the fixed true fraction of 0.458): the sketch-based rate reflects the same on-reference fraction the aligner does. The base-level Qualimap rate is computed only over reads that already mapped, so it saturates near 1.0 and is blind to the unmapped fraction; using it as ground truth is what previously made this metric look like a failure. This is agreement on a mixed sample once the unmapped noise is isolated, not an active contamination-detection claim.
RNA is the systematic exception
Scored independently against the transcriptome, RNA is the one workload where accuracy is materially lower (0.88–0.90) and where k-mer choice matters. Its sequence-change accuracy rises from r ≈ 0.53 at k1 = 51 to r ≈ 0.87 at k1 = 21, and the composite peaks near k1 = 21–25 before declining monotonically. This is consistent with edge-mer saturation on a short, isoform-redundant reference: a single change removes roughly k2 consecutive k-mers, so long extensions leave too few surviving k-mers and the inferred per-base rate runs to its ceiling. A residual ~1% floor in the alignment truth itself (cross-isoform mismatches under a splice-unaware aligner) further limits agreement at low divergence. Small core k-mers are therefore the appropriate operating point for transcriptomic input.
Why the best core k-mer size depends on the assay
The core k-mer size (k1) that gives the most accurate scores is not the same for every assay. For whole-genome, indel and metagenomic reads, accuracy climbs as k1 grows, so the best size is the largest one tested (composite accuracy, averaged over the edge and scale settings at each k1 rather than the best-achievable maximum, rises from about 0.95 at k1 = 21 to 0.97 at k1 = 51). For exome and RNA reads it does the reverse, falling as k1 grows (exome 0.95 down to 0.92, RNA 0.84 down to 0.64), so the best size is the smallest one tested. The dominant driver is visible directly in the sketches, and it centres on a single quantity: how many informative k-mers, meaning the k-mers a sample shares with the reference, survive in the sketch.
A larger core k-mer makes each estimate cleaner, because long k-mers rarely match the reference by chance, so the error, depth and coverage signals are sharper. But long k-mers are also rarer, so the sketch keeps fewer of them. Whether this cleaner-but-sparser trade pays off depends on how many informative k-mers the reference can supply. The dog genome (2.4 Gb) always supplies plenty: its reference sketch even grows, from about 201,000 to 225,000 distinct k-mers, as k1 rises, and a whole-genome sample still matches roughly 100,000 of them at k1 = 21 and 67,000 at k1 = 51. With that much signal to spare, the cleaner long-k-mer estimate wins, so the genomic assays do best at large k1.
The exome target and the transcriptome are tiny by comparison, so their sketches are starved of informative k-mers, and a larger k1 only makes them sparser. An exome sample matches only about 11,000 k-mers (only around 5% of the genome is on-target), and an RNA sample only about 4,000 at k1 = 21, dropping to 2,700 at k1 = 51 as the transcriptome sketch itself shrinks by roughly 30%. At the limit, an RNA sample at k1 = 51 has to estimate its entire error and mutation rate from only a handful of distinguishing k-mer observations (single digits for the low-divergence libraries), so the estimate turns noisy and its agreement with truth falls from 0.87 to 0.53. With so little signal, the smaller k-mer wins, so exome and RNA peak at k1 = 21.
The evidence points to sketch size, rather than any property of the sequences themselves, as the driver. Shrinking the sketch a different way, by coarsening the FracMinHash scale at a fixed k1 = 51, reproduces the same collapse: RNA's sequence-change agreement falls from 0.84 to 0.60 to 0.15 as the scale discards ten and then a hundred times more k-mers, with k1 never changing. Two plausible alternative explanations do not hold. The simulated error and mutation levels are identical across all five assays, so divergence cannot be responsible; and coverage runs the opposite way, since the exome reaches the highest on-target depths tested (up to 80×) yet still prefers the smallest k1, because extra reads add depth per k-mer but cannot add new informative k-mers.
Accuracy is robust to k, with one caveat
For genomic workloads the composite is nearly invariant to core k-mer size, edge extension and FracMinHash scale: a single compromise configuration (k1 = 31, k2-extension = 6, scale = 1,000) lands within 0.02 of every genomic workload's own optimum, and of the exome's. Only RNA benefits materially from tuning (+0.06 by moving to k1 = 21–25). Searching the full sweep instead of the fixed k1 ∈ {21, 31, 51} grid recovers only marginal accuracy (for example the genomic bundle rises from 0.980 to 0.984 by allowing k1 = 71), indicating the method is not sensitive to precise parameter choice for genomic and exome workloads within a sensible range (RNA excepted, as above).
One caveat on the yardstick itself: the alignment is treated as ground truth, but it is not
error-free. Under the most diverged conditions (5% error or mutation) bwa mis-maps and soft-clips a
fraction of reads, so the truth carries its own uncertainty, most visibly for RNA, where cross-isoform mapping
leaves a ~1% floor, but present for the genomic assays too. A perfect score is agreement with the aligner, not
with absolute reality. More broadly, these results are simulation-derived and specific to CanFam3.1; absolute
values will shift with reference completeness, read chemistry and divergence. The metrics and configurations
emphasized in the manuscript are selected for the reasons stated there; this page previews the entire
configuration space so the sensitivity of each conclusion to the k-mer parameters can be inspected below.
Downloads
The source tables and the computed scores behind every number on this page. Run the two build scripts on the two source inputs to reproduce the computed tables exactly.
| file | what it is |
|---|---|
| snipe_benchmark_bundle.zip | everything below except the large master table (tables, scripts, README) |
| Source inputs | |
| comparison_subset.tsv | snipe estimates vs the alignment ground truth, per sample and k-config. The main input. |
| consolidated_df_clean.tsv.gz | full master table (gzipped, about 20 MB); source of the read-level mapping ground truth. |
| Computed tables | |
| composite_scores.tsv | composite score per workload and config, all six flavors. |
| accuracy_atomic.tsv | per assay, config and metric: MAPE, Pearson r, accuracy. |
| composite_full_all_k.tsv | full per-config grid (the drill-down source). |
| best_config_per_combo.tsv | recommended config per workload. |
| headline_scores.tsv | best score per workload. |
| robustness.tsv | one global config versus each workload's own best. |
| score_app_data.json | the exact data object this page renders. |
| Build scripts | |
| build_composite_score.py | source inputs to the composite tables. |
| build_score_app_data.py | composite tables to the page data. |
| _readlevel_mapping.py | read-level mapping ground-truth helper. |
| README.txt | file descriptions, the k-mer grid and the grouping. |
Grid. The full k-mer grid is complete for every assay: core size k1 (11 values), edge extension k2 (2, 4, 6, 8, 10, 14, 18) and FracMinHash scale (3 values).