Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Python population genetics with scikit-allel. Read VCF files, compute allele frequencies, calculate diversity statistics, perform PCA, and run selection scans using GenotypeArray and HaplotypeArray data structures. Use when analyzing population genetics in Python.
.claude/skills/bio-population-genetics-scikit-allel-analysis/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-03 | ✗→✓ | ▲ Improved | 24% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 32% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 82% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 22% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 35% | 0% |
<!--
#
#
-->
Python library for population genetics analysis with efficient array data structures.
bashpip install scikit-allel # Optional: zarr for chunked storage pip install zarr
pythonimport allel callset = allel.read_vcf('data.vcf.gz') print(callset.keys()) # dict_keys(['samples', 'calldata/GT', 'variants/CHROM', 'variants/POS', 'variants/REF', 'variants/ALT', ...]) samples = callset['samples'] genotypes = callset['calldata/GT'] positions = callset['variants/POS'] chroms = callset['variants/CHROM']
pythoncallset = allel.read_vcf('data.vcf.gz', fields=['samples', 'calldata/GT', 'variants/POS', 'variants/CHROM', 'variants/QUAL']) callset = allel.read_vcf('data.vcf.gz', fields='*') # All fields callset = allel.read_vcf('data.vcf.gz', region='chr1:1000000-2000000', samples=['sample1', 'sample2'])
pythonimport zarr allel.vcf_to_zarr('large.vcf.gz', 'data.zarr', fields='*', overwrite=True) callset = zarr.open('data.zarr', mode='r') gt = allel.GenotypeArray(callset['calldata/GT'])
pythongt = allel.GenotypeArray(callset['calldata/GT']) print(gt.shape) # (n_variants, n_samples, ploidy) print(gt.n_variants) print(gt.n_samples) print(gt[0]) # Genotypes at first variant print(gt[:, 0]) # All variants for first sample
pythonac = gt.count_alleles() print(ac.shape) # (n_variants, n_alleles) af = ac.to_frequencies() is_segregating = ac.is_segregating() gt_filtered = gt.compress(is_segregating, axis=0)
pythonis_called = gt.is_called() is_missing = gt.is_missing() miss_per_variant = (~is_called).sum(axis=1) miss_per_sample = (~is_called).sum(axis=0) call_rate_variant = is_called.mean(axis=1) call_rate_sample = is_called.mean(axis=0)
pythonac = gt.count_alleles() ac_ref = ac[:, 0] ac_alt = ac[:, 1] af = ac.to_frequencies() maf = af.min(axis=1) n_singletons = (ac[:, 1] == 1).sum() n_doubletons = (ac[:, 1] == 2).sum()
pythonsubpops = { 'pop1': [0, 1, 2, 3, 4], 'pop2': [5, 6, 7, 8, 9] } ac_subpops = gt.count_alleles_subpops(subpops) ac_pop1 = ac_subpops['pop1'] ac_pop2 = ac_subpops['pop2']
pythonh = gt.to_haplotypes() print(h.shape) # (n_variants, n_haplotypes) print(h.n_haplotypes) ac_hap = h.count_alleles()
pythonimport allel import numpy as np gn = gt.to_n_alt(fill=-1) gn_filtered = gn[is_segregating] gn_imputed = np.where(gn_filtered < 0, 0, gn_filtered) coords, model = allel.pca(gn_imputed, n_components=10, scaler='patterson') print(coords.shape) # (n_samples, n_components)
pythonimport matplotlib.pyplot as plt plt.figure(figsize=(8, 6)) plt.scatter(coords[:, 0], coords[:, 1], c=population_labels) plt.xlabel('PC1') plt.ylabel('PC2') plt.savefig('pca.png')
pythonho = allel.heterozygosity_observed(gt) he = allel.heterozygosity_expected(ac, ploidy=2) mean_ho = np.mean(ho) mean_he = np.mean(he)
pythonpi = allel.sequence_diversity(positions, ac) print(f'Pi = {pi:.6f}') windows = allel.moving_statistic(positions, statistic=lambda x: allel.sequence_diversity(x, ac), size=10000, step=5000)
pythontheta_w = allel.watterson_theta(positions, ac) print(f'Theta_W = {theta_w:.6f}')
pythonsfs = allel.sfs(ac[:, 1]) plt.figure(figsize=(10, 5)) allel.plot_sfs(sfs) plt.savefig('sfs.png')
pythonsfs_folded = allel.sfs_folded(ac) plt.figure(figsize=(10, 5)) allel.plot_sfs_folded(sfs_folded) plt.savefig('sfs_folded.png')
pythonpos = np.array(positions) windows = np.arange(0, pos.max(), 100000) pi_windowed, windows_used, n_bases, counts = allel.windowed_diversity(pos, ac, size=100000, step=50000) plt.figure(figsize=(14, 4)) plt.plot(windows_used[:, 0], pi_windowed) plt.xlabel('Position') plt.ylabel('Pi') plt.savefig('pi_windows.png')
pythonpop1_idx = np.array([0, 1, 2, 3, 4]) pop2_idx = np.array([5, 6, 7, 8, 9]) gt_pop1 = gt.take(pop1_idx, axis=1) gt_pop2 = gt.take(pop2_idx, axis=1) ac_pop1 = gt_pop1.count_alleles() ac_pop2 = gt_pop2.count_alleles()
pythonis_snp = callset['variants/is_snp'] is_biallelic = ac.max_allele() == 1 is_segregating = ac.is_segregating() qual = callset['variants/QUAL'] is_high_qual = qual > 30 flt = is_snp & is_biallelic & is_segregating & is_high_qual gt_filtered = gt.compress(flt, axis=0) pos_filtered = positions[flt]
pythonimport allel import numpy as np callset = allel.read_vcf('data.vcf.gz', fields=['samples', 'calldata/GT', 'variants/POS']) gt = allel.GenotypeArray(callset['calldata/GT']) pos = callset['variants/POS'] samples = callset['samples'] ac = gt.count_alleles() flt = ac.is_segregating() & (ac.max_allele() == 1) gt = gt.compress(flt, axis=0) pos = pos[flt] ac = gt.count_alleles() print(f'Variants after filtering: {gt.n_variants}') print(f'Samples: {gt.n_samples}') print(f'Nucleotide diversity: {allel.sequence_diversity(pos, ac):.6f}') print(f'Mean Het observed: {allel.heterozygosity_observed(gt).mean():.4f}') gn = gt.to_n_alt(fill=-1) gn = np.where(gn < 0, 0, gn) coords, model = allel.pca(gn, n_components=10, scaler='patterson')
<!-- AUTHOR_SIGNATURE: 9a7f3c2e-MD-BABU-MIA-2026-MSSM-SECURE -->
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-10 | pass→pass | 9,482 | 2,185 | -77% | 1 | 1 | 0% | 1,910 | 2,733 | +43% | 0 | 0 | — |
case-16 | pass→pass | 4,975 | 2,804 | -44% | 1 | 1 | 0% | 969 | 2,876 | +197% | 0 | 0 | — |
case-05 | pass→pass | 5,360 | 3,482 | -35% | 1 | 1 | 0% | 999 | 3,028 | +203% | 0 | 0 | — |
case-21 | pass→pass | 16,782 | 10,913 | -35% | 1 | 1 | 0% | 3,127 | 4,560 | +46% | 0 | 0 | — |
case-22 | pass→pass | 13,375 | 9,572 | -28% | 1 | 1 | 0% | 2,509 | 4,380 | +75% | 0 | 0 | — |
case-01 | pass→pass | 9,374 | 3,016 | -68% | 1 | 1 | 0% | 1,780 | 2,900 | +63% | 0 | 0 | — |
case-02 | pass→pass | 10,908 | 4,955 | -55% | 1 | 1 | 0% | 2,277 | 3,398 | +49% | 0 | 0 | — |
case-03 | fail→pass | 18,158 | 9,774 | -46% | 1 | 1 | 0% | 3,430 | 4,268 | +24% | 0 | 0 | — |
case-04 | pass→pass | 11,398 | 4,293 | -62% | 1 | 1 | 0% | 2,292 | 3,063 | +34% | 0 | 0 | — |
case-06 | pass→pass | 14,444 | 2,729 | -81% | 1 | 1 | 0% | 3,082 | 2,908 | -6% | 0 | 0 | — |
case-07 | fail→pass | 16,435 | 10,505 | -36% | 1 | 1 | 0% | 3,331 | 4,386 | +32% | 0 | 0 | — |
case-08 | fail→pass | 9,171 | 3,649 | -60% | 1 | 1 | 0% | 1,664 | 3,027 | +82% | 0 | 0 | — |
case-09 | pass→pass | 10,558 | 6,652 | -37% | 1 | 1 | 0% | 1,874 | 3,481 | +86% | 0 | 0 | — |
case-15 | fail→pass | 15,001 | 5,854 | -61% | 1 | 1 | 0% | 2,967 | 3,610 | +22% | 0 | 0 | — |
case-11 | pass→pass | 10,059 | 4,040 | -60% | 1 | 1 | 0% | 2,070 | 3,069 | +48% | 0 | 0 | — |
case-12 | fail→pass | 11,028 | 2,561 | -77% | 1 | 1 | 0% | 2,114 | 2,854 | +35% | 0 | 0 | — |
case-13 | pass→pass | 9,725 | 5,646 | -42% | 1 | 1 | 0% | 1,968 | 3,548 | +80% | 0 | 0 | — |
case-14 | pass→pass | 6,105 | 2,638 | -57% | 1 | 1 | 0% | 1,100 | 2,877 | +162% | 0 | 0 | — |
case-17 | fail→pass | 12,388 | 5,435 | -56% | 1 | 1 | 0% | 2,397 | 3,325 | +39% | 0 | 0 | — |
case-18 | pass→pass | 11,047 | 3,314 | -70% | 1 | 1 | 0% | 2,150 | 2,962 | +38% | 0 | 0 | — |
case-19 | pass→pass | 9,561 | 5,470 | -43% | 1 | 1 | 0% | 1,834 | 3,286 | +79% | 0 | 0 | — |
case-20 | pass→pass | 17,753 | 15,828 | -11% | 1 | 1 | 0% | 3,866 | 5,846 | +51% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +27 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 7/24/2026 | +32% |
Other measured skills in the registry, with their headline benchmark lift.