Skip to main content

AdmixPy

Python implementation of ADMIXTOOLS-style f-statistics, qpAdm, and qpWave.

Fast f-statistics, qpAdm, and qpWave in Python.

Installation

Requires Python 3.10 or newer.

Using a virtual environment is recommended:

python3 -m venv venv
source venv/bin/activate

Install the latest release from PyPI:

python -m pip install --upgrade pip
python -m pip install admixpy

Check that the package imports:

python -c "import admixpy; print(admixpy.__version__)"

Updating

Upgrade an existing installation to the latest release:

python -m pip install --upgrade admixpy

Alternative: installing from source

Create and activate a virtual environment:

python3 -m venv venv
source venv/bin/activate

Install the package from pyproject.toml:

python -m pip install --upgrade pip
python -m pip install -e .

Examples

Supported input layouts include EIGENSTRAT text, packed AncestryMap, TGENO, and SNP-major PLINK binary files (.bed/.bim/.fam). For .geno/.snp/.ind inputs, the genotype layout is detected from the file header/size; TGENO can also be provided as .tgeno/.snp/.ind.

Basic API

The main convenience wrappers are:

admixpy.f2(data, pop1=None, pop2=None, *, unique_only=True,
           resampling="pairwise_counts", **kwargs)
admixpy.fst(data, pop1=None, pop2=None, *, unique_only=True,
            resampling="pairwise_counts", fst_aggregation="block_ratios",
            **kwargs)
admixpy.f3(data, pop1=None, pop2=None, pop3=None, *, unique_only=True,
           resampling="pairwise_counts", verbose=True, **kwargs)
admixpy.f4(data, pop1, pop2=None, pop3=None, pop4=None, *, comb=True,
           unique_only=True, afprod=False, verbose=True, **kwargs)
admixpy.qpwave(data, left, right, ranks=None, left_base=None,
               right_base=None, rcond=1e-10, diag=0.0, max_nfev=None,
               verbose=True, **kwargs)
admixpy.qpadm(data, target, left=None, right=None, sources=None,
              fudge=0.0001, fudge_twice=False, iterations=20, getcov=True,
              return_f4=False, return_stats=False, return_cov=False,
              verbose=True, *, popdrop=True, **kwargs)

data can be a supported genotype dataset prefix or precomputed f2 data. Population arguments can be strings or lists where the wrapper supports multiple combinations. For PLINK .bed/.bim/.fam input, population labels are read from the FID column of the .fam file.

For direct genotype input, f3, f4, qpwave, and qpadm default to allsnps=True, matching the ADMIXTOOLS1-style behavior of estimating each statistic from its available SNPs. For precomputed f2 input, allsnps defaults to False and the standard f2-based behavior is used. Pass allsnps=False to restrict direct-genotype models to SNPs shared across the required populations. Both direct-genotype modes use the direct per-SNP estimator and report the exact SNP count for each statistic; raw input is reduced to pairwise f2 values only when explicitly creating an f2 cache. An optional model column in an f4 combination table scopes the shared panel separately for each model.

Direct genotype f3 also defaults to allsnps=True and is calculated per SNP. By default, its corrected numerator is divided by unbiased target heterozygosity. Set outgroupmode=True to return the unnormalized f3 numerator; that raw mode is directly comparable to f2-derived f3 and to original qp3Pop outgroup mode after removing the latter's factor of 1000.

Direct f3 and f4 genotype calculations (including the f4 calculations for qpAdm and qpWave) read the genotype file once by default and hold the complete SNP-by-population allele-frequency and count tables in memory. For datasets that do not fit comfortably in RAM, set stream=True to use two bounded-memory passes with 250,000 SNPs per chunk by default. The chunk size can be adjusted with chunk_size.

qpAdm uses qpadm(data, target, left, right); there is no separate positional outgroup argument. sources is an alias for left, so supply only one of them. Both population lists must contain unique names, and left_base, if supplied, must equal the target. Invalid population counts are rejected before genotype data is read.

By default, qpAdm also fits every nonempty subset of the sources. This requires 2**len(left) - 1 subset fits. Use popdrop=False to skip this table while retaining the weights and rank tests; result.popdrop will be None. qpadm_multi(..., full_results=False) automatically skips subset fits and weight standard errors because it returns only the rank-test tables.

Population-drop chisq, p, and weights use the covariance of each retained subset, inverted after applying that subset's regularization. They match independent fits using the same stored SNP panel and block layout, including fudge_twice; dropping a source does not recover additional SNPs.

Nested comparisons include every one-source drop against the full model, followed by a feasible child with the smallest chi-square at each smaller size. nested_parent records the actual parent pattern. For these comparisons only, selected models are refitted using submatrices of the full model's regularized covariance. nested_chisq records those fit statistics, and chisqdiff and p_nested use their differences. Consequently, chisqdiff need not equal the difference between the standalone chisq entries. A materially negative difference from incomplete numerical convergence produces p_nested=NaN. These are nominal chi-square tests, without adjustment for model selection. The selected comparisons require at most 2*len(left) - 2 extra fits.

For direct use of qpadm_popdrop, pass the original covariance as cov=... alongside qinv to obtain the same subset regularization as qpadm. Without cov, the inverse of the supplied qinv is treated as an already regularized covariance; a singular qinv requires the original covariance explicitly.

For genotype batches, f4_model_cache retains block statistics and computes covariance only for the requested contrasts. Its cache.stats.cov is initially None; use f4_stats(cache, ...) or pass the cache to qpAdm/qpWave to obtain the required covariance. The cache records its resampling method in cache.stats.resampling. Requests using a different method raise an error; rebuild the cache with the desired resampling setting.

Direct f4 automatically batches suitable contrasts into matrix products. Repeated-population bias corrections, target-heterozygosity normalization, and other unsupported combinations retain the general per-contrast calculation. Pair-count computation and TGENO decoding also use fewer temporary arrays.

Lower-level helpers are also exported for direct use, including allele-frequency conversion (anygeno_to_afs, eigenstrat_to_afs, plink_to_afs, packedancestrymap_to_afs, tgeno_to_afs), f2 block IO and access (get_f2, read_f2, write_f2), and block/statistical utilities such as iter_geno_to_afs, f3_stats_from_geno, block_covariance, jackknife_cov, stats_to_loo, and est_to_loo.

SNP selection, missingness, and small samples

By default, f2 excludes SNPs with identical allele frequencies in every loaded population, while fst retains them. This matches the ADMIXTOOLS default but means the two statistics can use different SNP sets. Use poly_only=True to both calls when they should be directly comparable.

AdmixPy uses resampling="pairwise_counts" as default for data with missing genotypes: each population pair is weighted by the SNP observations actually available for that pair. Pairwise f2 and fst result tables include n. Set resampling="nominal_blocks" to reproduce the older behavior in which every pair uses nominal block sizes. Direct-genotype f4 with allsnps=True already uses per-statistic counts on a common SNP intersection. Direct-genotype f4 with allsnps=False uses the intersection shared by the requested model. Cached pairwise f3/f4 instead defines a pairwise-available estimator and cannot reconstruct either common intersection.

Different missing-block patterns can produce a covariance matrix with negative eigenvalues under pairwise resampling. qpAdm and qpWave reject such matrices instead of returning an invalid chi-square statistic. Inspect population coverage and usable blocks; recomputing from genotype input with allsnps=False uses a common SNP panel. Tiny negative eigenvalues attributable to floating-point roundoff are tolerated.

F2 cache creation and reading retain blocks with missing pair estimates by default (remove_na=False). Set remove_na=True to discard every block that is not finite (NaN) for all requested population pairs.

FST cache files additionally retain numerator and denominator sums. The default fst_aggregation="block_ratios" averages stored block estimates. Set fst_aggregation="pooled_components" to recompute full-data and leave-one-block-out FST as ratios of pooled numerator and denominator sums.

Bias-corrected f2 and FST require at least two independent allele observations in each population. SNP values with a count below two are excluded with a warning when apply_corr=True. Setting apply_corr=False explicitly requests the finite but sampling-biased raw estimate; the Hudson FST denominator remains (p1-p2)^2 + p1(1-p1) + p2(1-p2) in either mode.

Cache files without real per-pair SNP counts are rejected and must be rebuilt.

With minac2=2, populations that never have two allele observations are exempt from the minimum-count filter. If all populations are exempt, other SNP filters still apply. minac2=True instead requires two observations in every population.

Run an f4 statistic from a supported genotype dataset prefix:

import admixpy

prefix = "/path/to/dataset_prefix"

result = admixpy.f4(
    prefix,
    "Mbuti",
    "Germany_ViesenhaeuserHof_EN",
    "Sardinian",
    "French",
)

print(result)

qpAdm can be run the same way from a Python REPL:

>>> import admixpy as a
>>> prefix = "/path/to/dataset_prefix"
>>> target = "Sardinian"
>>> left = ["Turkey_N", "Russia_Samara_EBA_Yamnaya", "Luxembourg_Loschbour_Mesolithic", "Iran_GanjDareh_N"]
>>> right = ["Chimp", "Turkey_Epipaleolithic", "Georgia_KotiasKlde_Mesolithic", "Russia_Vologda_Mesolithic", "Switzerland_Epipaleolithic", "Iran_BeltCave_Mesolithic"]
>>> res = a.qpadm(prefix, target=target, left=left, right=right)
>>> res
QpAdmResult(target='Sardinian')

weights:
                           left weight     se     z
                       Turkey_N  0.686  0.013 52.45
      Russia_Samara_EBA_Yamnaya  0.102  0.012  8.54
Luxembourg_Loschbour_Mesolithic  0.119 0.0064 18.57
               Iran_GanjDareh_N  0.094  0.013  7.11

rankdrop:
f4rank dof   chisq         p  p_nested
     3   2    0.53     0.769 9.39e-242
     2   6 1123.16 2.03e-239         0
     1  12 3317.58         0         0
     0  20 6849.91         0       NaN

popdrop:
 pat                                                                    dropped f4rank dof   chisq         p  feasible status
0000                                                                                 3   2    0.53     0.769      True   PASS
0001                                                           Iran_GanjDareh_N      2   3   58.58  1.18e-12      True   FAIL
0010                                            Luxembourg_Loschbour_Mesolithic      2   3   370.2  6.29e-80     False   FAIL
0100                                                  Russia_Samara_EBA_Yamnaya      2   3   73.09  9.29e-16      True   FAIL
1000                                                                   Turkey_N      2   3  825.23 1.46e-178     False   FAIL
 ...

Citation

AdmixPy implements methods from Patterson et al. (2012) and Maier et al. (2023).

License

MIT License .

Release files for admixpy 1.0.6

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

Source distribution (sdist)

Source distribution for admixpy 1.0.6
File Size Uploaded
admixpy-1.0.6.tar.gz 68.3 kB Details

Built distribution (wheel)

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

Total release size: 116.0 kB

Release files / admixpy-1.0.6.tar.gz

Download URL admixpy-1.0.6.tar.gz
Size 68.3 kB
Tags Source
SHA-256 checksum
How to use checksums
d91715da8f3acf5567f9a50251120c63920766d09b56e75cadb11519d3b48c46
BLAKE2b-256 checksum
How to use checksums
148143323f4a0c56baaf14e83a2a0409b9b3ede1e40b074e8afc44fe882a748d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / admixpy-1.0.6-py3-none-any.whl

Download URL admixpy-1.0.6-py3-none-any.whl
Size 47.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c5561b184dc1026a2bbbb823ee655d021bc74e6d1336cd7fea4e851dbc9dd876
BLAKE2b-256 checksum
How to use checksums
d79e4c89199627b84a97f2c6950a3e7a1df35d5cbc3e8062b067c9d762a66562
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release history Release notifications | RSS feed

1.0.8

2 release files

1.0.7

2 release files

This release

1.0.6 This release

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

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