admixpy 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- admixpy-1.0.0/CHANGELOG.md +21 -0
- admixpy-1.0.0/LICENSE +21 -0
- admixpy-1.0.0/MANIFEST.in +1 -0
- admixpy-1.0.0/PKG-INFO +251 -0
- admixpy-1.0.0/README.md +224 -0
- admixpy-1.0.0/admixpy/__init__.py +126 -0
- admixpy-1.0.0/admixpy/fstats.py +3280 -0
- admixpy-1.0.0/admixpy/genotypes.py +885 -0
- admixpy-1.0.0/admixpy.egg-info/PKG-INFO +251 -0
- admixpy-1.0.0/admixpy.egg-info/SOURCES.txt +14 -0
- admixpy-1.0.0/admixpy.egg-info/dependency_links.txt +1 -0
- admixpy-1.0.0/admixpy.egg-info/requires.txt +3 -0
- admixpy-1.0.0/admixpy.egg-info/top_level.txt +1 -0
- admixpy-1.0.0/pyproject.toml +39 -0
- admixpy-1.0.0/setup.cfg +4 -0
- admixpy-1.0.0/tests/test_fstats_correctness.py +1108 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to AdmixPy are documented in this file.
|
|
4
|
+
|
|
5
|
+
## 1.0.0 - 2026-08-10
|
|
6
|
+
|
|
7
|
+
First stable release.
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
- Fast whole-dataset f-statistics, qpAdm, and qpWave analysis.
|
|
12
|
+
- f2, Hudson FST, f3, and f4 statistics with block-jackknife uncertainty.
|
|
13
|
+
- qpAdm and qpWave model fitting, rank tests, and qpAdm population-drop models.
|
|
14
|
+
- Direct EIGENSTRAT, PACKEDANCESTRYMAP, TGENO, and SNP-major PLINK input.
|
|
15
|
+
- Precomputed f2 block caches with per-pair SNP counts and FST components.
|
|
16
|
+
- Bounded-memory streaming for direct f3 and f4 workflows.
|
|
17
|
+
- Explicit missing-data, SNP-selection, and pseudohaploid correction options.
|
|
18
|
+
|
|
19
|
+
### Requirements
|
|
20
|
+
|
|
21
|
+
- Python 3.10 or newer is required.
|
admixpy-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 system0x7
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
include CHANGELOG.md
|
admixpy-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: admixpy
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Fast Python implementation of ADMIXTOOLS-style f-statistics, qpadm, and qpwave
|
|
5
|
+
Author: system0x7
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/system0x7/admixpy
|
|
8
|
+
Project-URL: Repository, https://github.com/system0x7/admixpy
|
|
9
|
+
Project-URL: Issues, https://github.com/system0x7/admixpy/issues
|
|
10
|
+
Keywords: population genetics,f-statistics,qpadm,qpwave,admixture
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: numpy
|
|
24
|
+
Requires-Dist: pandas
|
|
25
|
+
Requires-Dist: scipy
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# AdmixPy
|
|
29
|
+
|
|
30
|
+
Fast Python implementation of ADMIXTOOLS-style f-statistics, qpAdm, and qpWave.
|
|
31
|
+
|
|
32
|
+
> Fast f-statistics, qpAdm, and qpWave in Python.
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
Requires Python 3.10 or newer.
|
|
37
|
+
|
|
38
|
+
Install the latest release from PyPI:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
python -m pip install admixpy
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Check that the package imports:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
python -c "import admixpy; print(admixpy.__version__)"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Installing from source
|
|
51
|
+
|
|
52
|
+
Create and activate a virtual environment:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
python3 -m venv venv
|
|
56
|
+
source venv/bin/activate
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Install the package from `pyproject.toml`:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
python -m pip install --upgrade pip
|
|
63
|
+
python -m pip install -e .
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Updating an existing clone
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
cd /path/to/admixpy
|
|
70
|
+
git pull --ff-only
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
After updating, run the two installation commands in Setup again.
|
|
74
|
+
|
|
75
|
+
## Alternative
|
|
76
|
+
|
|
77
|
+
If you only want to install the dependencies without installing the package:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
python -m pip install -r requirements.txt
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Examples
|
|
84
|
+
|
|
85
|
+
Supported input layouts include EIGENSTRAT text, packed AncestryMap, TGENO, and
|
|
86
|
+
SNP-major PLINK binary files (`.bed/.bim/.fam`). For `.geno/.snp/.ind` inputs,
|
|
87
|
+
the genotype layout is detected from the file header/size; TGENO can also be provided as `.tgeno/.snp/.ind`.
|
|
88
|
+
|
|
89
|
+
## Basic API
|
|
90
|
+
|
|
91
|
+
The main convenience wrappers are:
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
admixpy.f2(data, pop1=None, pop2=None, *, unique_only=True,
|
|
95
|
+
resampling="pairwise_counts", **kwargs)
|
|
96
|
+
admixpy.fst(data, pop1=None, pop2=None, *, unique_only=True,
|
|
97
|
+
resampling="pairwise_counts", fst_aggregation="block_ratios",
|
|
98
|
+
**kwargs)
|
|
99
|
+
admixpy.f3(data, pop1=None, pop2=None, pop3=None, *, unique_only=True,
|
|
100
|
+
resampling="pairwise_counts", verbose=True, **kwargs)
|
|
101
|
+
admixpy.f4(data, pop1, pop2=None, pop3=None, pop4=None, *, comb=True,
|
|
102
|
+
unique_only=True, afprod=False, verbose=True, **kwargs)
|
|
103
|
+
admixpy.qpwave(data, left, right, ranks=None, left_base=None,
|
|
104
|
+
right_base=None, rcond=1e-10, diag=0.0, max_nfev=None,
|
|
105
|
+
verbose=True, **kwargs)
|
|
106
|
+
admixpy.qpadm(data, target, left=None, right=None, sources=None,
|
|
107
|
+
fudge=0.0001, fudge_twice=False, iterations=20, getcov=True,
|
|
108
|
+
return_f4=False, return_stats=False, return_cov=False,
|
|
109
|
+
verbose=True, **kwargs)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The main convenience wrappers are `f2`, `fst`, `f3`, `f4`, `qpwave`, and
|
|
113
|
+
`qpadm`.
|
|
114
|
+
|
|
115
|
+
`data` can be a supported genotype dataset prefix or precomputed f2 data.
|
|
116
|
+
Population arguments can be strings or lists where the wrapper supports multiple
|
|
117
|
+
combinations. For PLINK `.bed/.bim/.fam` input, population labels are read from
|
|
118
|
+
the FID column of the `.fam` file.
|
|
119
|
+
|
|
120
|
+
For direct genotype input, `f3`, `f4`, `qpwave`, and `qpadm` default to
|
|
121
|
+
`allsnps=True`, matching the ADMIXTOOLS1-style behavior of estimating each
|
|
122
|
+
statistic from its available SNPs. For precomputed f2 input, `allsnps` defaults
|
|
123
|
+
to `False` and the standard f2-based behavior is used. Pass `allsnps=False` to
|
|
124
|
+
restrict direct-genotype models to SNPs shared across the required populations.
|
|
125
|
+
|
|
126
|
+
Direct genotype `f3` also defaults to `allsnps=True` and is calculated per SNP.
|
|
127
|
+
By default, its corrected numerator is divided by unbiased target
|
|
128
|
+
heterozygosity. Set `outgroupmode=True` to return the unnormalized f3 numerator;
|
|
129
|
+
that raw mode is directly comparable to f2-derived f3 and to original `qp3Pop`
|
|
130
|
+
outgroup mode after removing the latter's factor of 1000.
|
|
131
|
+
|
|
132
|
+
| Data | Scope | Recommended setting |
|
|
133
|
+
|---|---|---|
|
|
134
|
+
| Known modern diploid data | All direct genotype statistics | Keep defaults (ploidy auto-detected), or set `adjust_pseudohaploid=False` to force known diploid data |
|
|
135
|
+
| Ancient or mixed-ploidy data | All direct genotype statistics | `adjust_pseudohaploid=True, apply_corr=True` (auto-detected per sample) |
|
|
136
|
+
| ADMIXTOOLS2-normalized direct f3 | f3 only | `outgroupmode=False` (default) |
|
|
137
|
+
| Raw/original outgroup f3 | f3 only | `outgroupmode=True` |
|
|
138
|
+
| Diploid singleton target or repeated source | f3 only | Keep `apply_corr=True`; two called alleles make correction possible |
|
|
139
|
+
| Pseudohaploid singleton used only as a distinct source | f3 only | Allowed with `apply_corr=True` because it occurs linearly |
|
|
140
|
+
| Pseudohaploid singleton target or repeated source | f3 only | Unbiased correction is not possible; affected SNPs are excluded |
|
|
141
|
+
| Intentionally biased singleton estimate | f3 only | `outgroupmode=True, apply_corr=False`; exploratory/legacy |
|
|
142
|
+
| Missingness differs among populations or blocks | f2, FST, f3, and cached f4 | `resampling="pairwise_counts"` (default) |
|
|
143
|
+
| In-memory blocks without SNP counts | Precomputed-block workflows | `resampling="nominal_blocks"`; incomplete on-disk caches must be rebuilt |
|
|
144
|
+
| Maximum available SNPs per combination | Direct f3/f4, qpWave, and qpAdm | `allsnps=True` (direct-genotype default) |
|
|
145
|
+
| Common SNP set across a model | Direct f3/f4, qpWave, and qpAdm | `allsnps=False` |
|
|
146
|
+
| Use only polymorphic sites | Direct f-statistics | `poly_only=True` (drops non-polymorphic sites) |
|
|
147
|
+
|
|
148
|
+
Direct f3 and f4 genotype calculations (including the f4 calculations
|
|
149
|
+
for qpAdm and qpWave) read the genotype file once by default and hold the
|
|
150
|
+
complete SNP-by-population allele-frequency and count tables in memory. For
|
|
151
|
+
datasets that do not fit comfortably in RAM, set `stream=True` to use two
|
|
152
|
+
bounded-memory passes with 250,000 SNPs per chunk by default. The chunk size
|
|
153
|
+
can be adjusted with `chunk_size`.
|
|
154
|
+
|
|
155
|
+
Lower-level helpers are also exported for direct use, including allele-frequency
|
|
156
|
+
conversion (`anygeno_to_afs`, `eigenstrat_to_afs`, `plink_to_afs`,
|
|
157
|
+
`packedancestrymap_to_afs`, `tgeno_to_afs`), f2 block IO and access
|
|
158
|
+
(`get_f2`, `read_f2`, `write_f2`), and block/statistical utilities such as
|
|
159
|
+
`iter_geno_to_afs`, `f3_stats_from_geno`, `block_covariance`,
|
|
160
|
+
`jackknife_cov`, `stats_to_loo`, and `est_to_loo`.
|
|
161
|
+
|
|
162
|
+
### SNP selection, missingness, and small samples
|
|
163
|
+
|
|
164
|
+
By default, `f2` excludes SNPs with identical allele frequencies in every
|
|
165
|
+
loaded population, while `fst` retains them. This matches the ADMIXTOOLS
|
|
166
|
+
default but means the two statistics can use different SNP sets. Use
|
|
167
|
+
`poly_only=True` to both calls when they should be directly comparable.
|
|
168
|
+
|
|
169
|
+
AdmixPy uses `resampling="pairwise_counts"` as default for data
|
|
170
|
+
with missing genotypes: each population pair is weighted by the SNP
|
|
171
|
+
observations actually available for that pair. Pairwise `f2` and `fst` result
|
|
172
|
+
tables include `n`. Set `resampling="nominal_blocks"` to reproduce the older
|
|
173
|
+
behavior in which every pair uses nominal block sizes. Raw-genotype f4 with
|
|
174
|
+
`allsnps=True` already uses per-statistic counts on a common SNP intersection.
|
|
175
|
+
Cached pairwise f3/f4 instead defines a pairwise-available estimator and cannot
|
|
176
|
+
reconstruct that common intersection.
|
|
177
|
+
|
|
178
|
+
FST cache files additionally retain numerator and denominator sums. The
|
|
179
|
+
default `fst_aggregation="block_ratios"` averages stored block estimates.
|
|
180
|
+
Set `fst_aggregation="pooled_components"` to recompute full-data and
|
|
181
|
+
leave-one-block-out FST as ratios of pooled numerator and denominator sums.
|
|
182
|
+
|
|
183
|
+
Bias-corrected f2 and FST require at least two independent allele observations
|
|
184
|
+
in each population. SNP values with a count below two are excluded with a
|
|
185
|
+
warning when `apply_corr=True`. Setting `apply_corr=False` explicitly requests
|
|
186
|
+
the finite but sampling-biased raw estimate; the Hudson FST denominator remains
|
|
187
|
+
`(p1-p2)^2 + p1(1-p1) + p2(1-p2)` in either mode.
|
|
188
|
+
|
|
189
|
+
Cache files without real per-pair SNP counts are rejected and must be rebuilt.
|
|
190
|
+
|
|
191
|
+
Run an f4 statistic from a supported genotype dataset prefix:
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
import admixpy
|
|
195
|
+
|
|
196
|
+
prefix = "/path/to/dataset_prefix"
|
|
197
|
+
|
|
198
|
+
result = admixpy.f4(
|
|
199
|
+
prefix,
|
|
200
|
+
"Mbuti",
|
|
201
|
+
"Germany_ViesenhaeuserHof_EN",
|
|
202
|
+
"Sardinian",
|
|
203
|
+
"French",
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
print(result)
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
qpAdm can be run the same way from a Python REPL:
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
>>> import admixpy as a
|
|
213
|
+
>>> prefix = "/path/to/dataset_prefix"
|
|
214
|
+
>>> target = "Sardinian"
|
|
215
|
+
>>> left = ["Turkey_N", "Russia_Samara_EBA_Yamnaya", "Luxembourg_Loschbour_Mesolithic", "Iran_GanjDareh_N"]
|
|
216
|
+
>>> right = ["Chimp", "Turkey_Epipaleolithic", "Georgia_KotiasKlde_Mesolithic", "Russia_Vologda_Mesolithic", "Switzerland_Epipaleolithic", "Iran_BeltCave_Mesolithic"]
|
|
217
|
+
>>> res = a.qpadm(prefix, target=target, left=left, right=right)
|
|
218
|
+
>>> res
|
|
219
|
+
QpAdmResult(target='Sardinian')
|
|
220
|
+
|
|
221
|
+
weights:
|
|
222
|
+
left weight se z
|
|
223
|
+
Turkey_N 0.686 0.013 52.45
|
|
224
|
+
Russia_Samara_EBA_Yamnaya 0.102 0.012 8.54
|
|
225
|
+
Luxembourg_Loschbour_Mesolithic 0.119 0.0064 18.57
|
|
226
|
+
Iran_GanjDareh_N 0.094 0.013 7.11
|
|
227
|
+
|
|
228
|
+
rankdrop:
|
|
229
|
+
f4rank dof chisq p p_nested
|
|
230
|
+
3 2 0.53 0.769 9.39e-242
|
|
231
|
+
2 6 1123.16 2.03e-239 0
|
|
232
|
+
1 12 3317.58 0 0
|
|
233
|
+
0 20 6849.91 0 NaN
|
|
234
|
+
|
|
235
|
+
popdrop:
|
|
236
|
+
pat dropped f4rank dof chisq p feasible status
|
|
237
|
+
0000 3 2 0.53 0.769 True PASS
|
|
238
|
+
0001 Iran_GanjDareh_N 2 3 58.58 1.18e-12 True FAIL
|
|
239
|
+
0010 Luxembourg_Loschbour_Mesolithic 2 3 370.2 6.29e-80 False FAIL
|
|
240
|
+
0100 Russia_Samara_EBA_Yamnaya 2 3 73.09 9.29e-16 True FAIL
|
|
241
|
+
1000 Turkey_N 2 3 825.23 1.46e-178 False FAIL
|
|
242
|
+
...
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Citation
|
|
246
|
+
|
|
247
|
+
AdmixPy implements methods from Patterson et al. (2012) and Maier et al. (2023).
|
|
248
|
+
|
|
249
|
+
## License
|
|
250
|
+
|
|
251
|
+
[MIT License](LICENSE) .
|
admixpy-1.0.0/README.md
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# AdmixPy
|
|
2
|
+
|
|
3
|
+
Fast Python implementation of ADMIXTOOLS-style f-statistics, qpAdm, and qpWave.
|
|
4
|
+
|
|
5
|
+
> Fast f-statistics, qpAdm, and qpWave in Python.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Requires Python 3.10 or newer.
|
|
10
|
+
|
|
11
|
+
Install the latest release from PyPI:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
python -m pip install admixpy
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Check that the package imports:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
python -c "import admixpy; print(admixpy.__version__)"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Installing from source
|
|
24
|
+
|
|
25
|
+
Create and activate a virtual environment:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
python3 -m venv venv
|
|
29
|
+
source venv/bin/activate
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Install the package from `pyproject.toml`:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
python -m pip install --upgrade pip
|
|
36
|
+
python -m pip install -e .
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Updating an existing clone
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
cd /path/to/admixpy
|
|
43
|
+
git pull --ff-only
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
After updating, run the two installation commands in Setup again.
|
|
47
|
+
|
|
48
|
+
## Alternative
|
|
49
|
+
|
|
50
|
+
If you only want to install the dependencies without installing the package:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
python -m pip install -r requirements.txt
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Examples
|
|
57
|
+
|
|
58
|
+
Supported input layouts include EIGENSTRAT text, packed AncestryMap, TGENO, and
|
|
59
|
+
SNP-major PLINK binary files (`.bed/.bim/.fam`). For `.geno/.snp/.ind` inputs,
|
|
60
|
+
the genotype layout is detected from the file header/size; TGENO can also be provided as `.tgeno/.snp/.ind`.
|
|
61
|
+
|
|
62
|
+
## Basic API
|
|
63
|
+
|
|
64
|
+
The main convenience wrappers are:
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
admixpy.f2(data, pop1=None, pop2=None, *, unique_only=True,
|
|
68
|
+
resampling="pairwise_counts", **kwargs)
|
|
69
|
+
admixpy.fst(data, pop1=None, pop2=None, *, unique_only=True,
|
|
70
|
+
resampling="pairwise_counts", fst_aggregation="block_ratios",
|
|
71
|
+
**kwargs)
|
|
72
|
+
admixpy.f3(data, pop1=None, pop2=None, pop3=None, *, unique_only=True,
|
|
73
|
+
resampling="pairwise_counts", verbose=True, **kwargs)
|
|
74
|
+
admixpy.f4(data, pop1, pop2=None, pop3=None, pop4=None, *, comb=True,
|
|
75
|
+
unique_only=True, afprod=False, verbose=True, **kwargs)
|
|
76
|
+
admixpy.qpwave(data, left, right, ranks=None, left_base=None,
|
|
77
|
+
right_base=None, rcond=1e-10, diag=0.0, max_nfev=None,
|
|
78
|
+
verbose=True, **kwargs)
|
|
79
|
+
admixpy.qpadm(data, target, left=None, right=None, sources=None,
|
|
80
|
+
fudge=0.0001, fudge_twice=False, iterations=20, getcov=True,
|
|
81
|
+
return_f4=False, return_stats=False, return_cov=False,
|
|
82
|
+
verbose=True, **kwargs)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The main convenience wrappers are `f2`, `fst`, `f3`, `f4`, `qpwave`, and
|
|
86
|
+
`qpadm`.
|
|
87
|
+
|
|
88
|
+
`data` can be a supported genotype dataset prefix or precomputed f2 data.
|
|
89
|
+
Population arguments can be strings or lists where the wrapper supports multiple
|
|
90
|
+
combinations. For PLINK `.bed/.bim/.fam` input, population labels are read from
|
|
91
|
+
the FID column of the `.fam` file.
|
|
92
|
+
|
|
93
|
+
For direct genotype input, `f3`, `f4`, `qpwave`, and `qpadm` default to
|
|
94
|
+
`allsnps=True`, matching the ADMIXTOOLS1-style behavior of estimating each
|
|
95
|
+
statistic from its available SNPs. For precomputed f2 input, `allsnps` defaults
|
|
96
|
+
to `False` and the standard f2-based behavior is used. Pass `allsnps=False` to
|
|
97
|
+
restrict direct-genotype models to SNPs shared across the required populations.
|
|
98
|
+
|
|
99
|
+
Direct genotype `f3` also defaults to `allsnps=True` and is calculated per SNP.
|
|
100
|
+
By default, its corrected numerator is divided by unbiased target
|
|
101
|
+
heterozygosity. Set `outgroupmode=True` to return the unnormalized f3 numerator;
|
|
102
|
+
that raw mode is directly comparable to f2-derived f3 and to original `qp3Pop`
|
|
103
|
+
outgroup mode after removing the latter's factor of 1000.
|
|
104
|
+
|
|
105
|
+
| Data | Scope | Recommended setting |
|
|
106
|
+
|---|---|---|
|
|
107
|
+
| Known modern diploid data | All direct genotype statistics | Keep defaults (ploidy auto-detected), or set `adjust_pseudohaploid=False` to force known diploid data |
|
|
108
|
+
| Ancient or mixed-ploidy data | All direct genotype statistics | `adjust_pseudohaploid=True, apply_corr=True` (auto-detected per sample) |
|
|
109
|
+
| ADMIXTOOLS2-normalized direct f3 | f3 only | `outgroupmode=False` (default) |
|
|
110
|
+
| Raw/original outgroup f3 | f3 only | `outgroupmode=True` |
|
|
111
|
+
| Diploid singleton target or repeated source | f3 only | Keep `apply_corr=True`; two called alleles make correction possible |
|
|
112
|
+
| Pseudohaploid singleton used only as a distinct source | f3 only | Allowed with `apply_corr=True` because it occurs linearly |
|
|
113
|
+
| Pseudohaploid singleton target or repeated source | f3 only | Unbiased correction is not possible; affected SNPs are excluded |
|
|
114
|
+
| Intentionally biased singleton estimate | f3 only | `outgroupmode=True, apply_corr=False`; exploratory/legacy |
|
|
115
|
+
| Missingness differs among populations or blocks | f2, FST, f3, and cached f4 | `resampling="pairwise_counts"` (default) |
|
|
116
|
+
| In-memory blocks without SNP counts | Precomputed-block workflows | `resampling="nominal_blocks"`; incomplete on-disk caches must be rebuilt |
|
|
117
|
+
| Maximum available SNPs per combination | Direct f3/f4, qpWave, and qpAdm | `allsnps=True` (direct-genotype default) |
|
|
118
|
+
| Common SNP set across a model | Direct f3/f4, qpWave, and qpAdm | `allsnps=False` |
|
|
119
|
+
| Use only polymorphic sites | Direct f-statistics | `poly_only=True` (drops non-polymorphic sites) |
|
|
120
|
+
|
|
121
|
+
Direct f3 and f4 genotype calculations (including the f4 calculations
|
|
122
|
+
for qpAdm and qpWave) read the genotype file once by default and hold the
|
|
123
|
+
complete SNP-by-population allele-frequency and count tables in memory. For
|
|
124
|
+
datasets that do not fit comfortably in RAM, set `stream=True` to use two
|
|
125
|
+
bounded-memory passes with 250,000 SNPs per chunk by default. The chunk size
|
|
126
|
+
can be adjusted with `chunk_size`.
|
|
127
|
+
|
|
128
|
+
Lower-level helpers are also exported for direct use, including allele-frequency
|
|
129
|
+
conversion (`anygeno_to_afs`, `eigenstrat_to_afs`, `plink_to_afs`,
|
|
130
|
+
`packedancestrymap_to_afs`, `tgeno_to_afs`), f2 block IO and access
|
|
131
|
+
(`get_f2`, `read_f2`, `write_f2`), and block/statistical utilities such as
|
|
132
|
+
`iter_geno_to_afs`, `f3_stats_from_geno`, `block_covariance`,
|
|
133
|
+
`jackknife_cov`, `stats_to_loo`, and `est_to_loo`.
|
|
134
|
+
|
|
135
|
+
### SNP selection, missingness, and small samples
|
|
136
|
+
|
|
137
|
+
By default, `f2` excludes SNPs with identical allele frequencies in every
|
|
138
|
+
loaded population, while `fst` retains them. This matches the ADMIXTOOLS
|
|
139
|
+
default but means the two statistics can use different SNP sets. Use
|
|
140
|
+
`poly_only=True` to both calls when they should be directly comparable.
|
|
141
|
+
|
|
142
|
+
AdmixPy uses `resampling="pairwise_counts"` as default for data
|
|
143
|
+
with missing genotypes: each population pair is weighted by the SNP
|
|
144
|
+
observations actually available for that pair. Pairwise `f2` and `fst` result
|
|
145
|
+
tables include `n`. Set `resampling="nominal_blocks"` to reproduce the older
|
|
146
|
+
behavior in which every pair uses nominal block sizes. Raw-genotype f4 with
|
|
147
|
+
`allsnps=True` already uses per-statistic counts on a common SNP intersection.
|
|
148
|
+
Cached pairwise f3/f4 instead defines a pairwise-available estimator and cannot
|
|
149
|
+
reconstruct that common intersection.
|
|
150
|
+
|
|
151
|
+
FST cache files additionally retain numerator and denominator sums. The
|
|
152
|
+
default `fst_aggregation="block_ratios"` averages stored block estimates.
|
|
153
|
+
Set `fst_aggregation="pooled_components"` to recompute full-data and
|
|
154
|
+
leave-one-block-out FST as ratios of pooled numerator and denominator sums.
|
|
155
|
+
|
|
156
|
+
Bias-corrected f2 and FST require at least two independent allele observations
|
|
157
|
+
in each population. SNP values with a count below two are excluded with a
|
|
158
|
+
warning when `apply_corr=True`. Setting `apply_corr=False` explicitly requests
|
|
159
|
+
the finite but sampling-biased raw estimate; the Hudson FST denominator remains
|
|
160
|
+
`(p1-p2)^2 + p1(1-p1) + p2(1-p2)` in either mode.
|
|
161
|
+
|
|
162
|
+
Cache files without real per-pair SNP counts are rejected and must be rebuilt.
|
|
163
|
+
|
|
164
|
+
Run an f4 statistic from a supported genotype dataset prefix:
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
import admixpy
|
|
168
|
+
|
|
169
|
+
prefix = "/path/to/dataset_prefix"
|
|
170
|
+
|
|
171
|
+
result = admixpy.f4(
|
|
172
|
+
prefix,
|
|
173
|
+
"Mbuti",
|
|
174
|
+
"Germany_ViesenhaeuserHof_EN",
|
|
175
|
+
"Sardinian",
|
|
176
|
+
"French",
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
print(result)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
qpAdm can be run the same way from a Python REPL:
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
>>> import admixpy as a
|
|
186
|
+
>>> prefix = "/path/to/dataset_prefix"
|
|
187
|
+
>>> target = "Sardinian"
|
|
188
|
+
>>> left = ["Turkey_N", "Russia_Samara_EBA_Yamnaya", "Luxembourg_Loschbour_Mesolithic", "Iran_GanjDareh_N"]
|
|
189
|
+
>>> right = ["Chimp", "Turkey_Epipaleolithic", "Georgia_KotiasKlde_Mesolithic", "Russia_Vologda_Mesolithic", "Switzerland_Epipaleolithic", "Iran_BeltCave_Mesolithic"]
|
|
190
|
+
>>> res = a.qpadm(prefix, target=target, left=left, right=right)
|
|
191
|
+
>>> res
|
|
192
|
+
QpAdmResult(target='Sardinian')
|
|
193
|
+
|
|
194
|
+
weights:
|
|
195
|
+
left weight se z
|
|
196
|
+
Turkey_N 0.686 0.013 52.45
|
|
197
|
+
Russia_Samara_EBA_Yamnaya 0.102 0.012 8.54
|
|
198
|
+
Luxembourg_Loschbour_Mesolithic 0.119 0.0064 18.57
|
|
199
|
+
Iran_GanjDareh_N 0.094 0.013 7.11
|
|
200
|
+
|
|
201
|
+
rankdrop:
|
|
202
|
+
f4rank dof chisq p p_nested
|
|
203
|
+
3 2 0.53 0.769 9.39e-242
|
|
204
|
+
2 6 1123.16 2.03e-239 0
|
|
205
|
+
1 12 3317.58 0 0
|
|
206
|
+
0 20 6849.91 0 NaN
|
|
207
|
+
|
|
208
|
+
popdrop:
|
|
209
|
+
pat dropped f4rank dof chisq p feasible status
|
|
210
|
+
0000 3 2 0.53 0.769 True PASS
|
|
211
|
+
0001 Iran_GanjDareh_N 2 3 58.58 1.18e-12 True FAIL
|
|
212
|
+
0010 Luxembourg_Loschbour_Mesolithic 2 3 370.2 6.29e-80 False FAIL
|
|
213
|
+
0100 Russia_Samara_EBA_Yamnaya 2 3 73.09 9.29e-16 True FAIL
|
|
214
|
+
1000 Turkey_N 2 3 825.23 1.46e-178 False FAIL
|
|
215
|
+
...
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Citation
|
|
219
|
+
|
|
220
|
+
AdmixPy implements methods from Patterson et al. (2012) and Maier et al. (2023).
|
|
221
|
+
|
|
222
|
+
## License
|
|
223
|
+
|
|
224
|
+
[MIT License](LICENSE) .
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
__version__ = "1.0.0"
|
|
2
|
+
|
|
3
|
+
from .fstats import (
|
|
4
|
+
BlockStats,
|
|
5
|
+
F2Blocks,
|
|
6
|
+
F4BlockCache,
|
|
7
|
+
F4ModelCache,
|
|
8
|
+
QpAdmResult,
|
|
9
|
+
QpWaveStats,
|
|
10
|
+
afs_to_f2_blocks,
|
|
11
|
+
block_covariance,
|
|
12
|
+
est_to_loo,
|
|
13
|
+
f2,
|
|
14
|
+
f2_from_geno,
|
|
15
|
+
f3,
|
|
16
|
+
f3_from_f2,
|
|
17
|
+
f3_stats_from_geno,
|
|
18
|
+
f4,
|
|
19
|
+
f4_model_cache,
|
|
20
|
+
f4_from_f2,
|
|
21
|
+
f4_stats,
|
|
22
|
+
f4_stats_from_geno,
|
|
23
|
+
format_fstats,
|
|
24
|
+
fst,
|
|
25
|
+
get_f2,
|
|
26
|
+
jackknife_cov,
|
|
27
|
+
jack_vec_stats,
|
|
28
|
+
mats_to_aparr,
|
|
29
|
+
mats_to_ctarr,
|
|
30
|
+
mats_to_f2arr,
|
|
31
|
+
qpdstat,
|
|
32
|
+
qp3pop,
|
|
33
|
+
qpadm,
|
|
34
|
+
qpadm_fit,
|
|
35
|
+
qpadm_multi,
|
|
36
|
+
qpadm_popdrop,
|
|
37
|
+
qpadm_rankdrop,
|
|
38
|
+
qpadm_weights,
|
|
39
|
+
qpwave,
|
|
40
|
+
qpwave_f4stats,
|
|
41
|
+
qpwave_multi,
|
|
42
|
+
qpwave_ranktest,
|
|
43
|
+
read_f2,
|
|
44
|
+
stats_to_loo,
|
|
45
|
+
write_f2,
|
|
46
|
+
)
|
|
47
|
+
from .genotypes import (
|
|
48
|
+
AfData,
|
|
49
|
+
anygeno_to_afs,
|
|
50
|
+
detect_geno_format,
|
|
51
|
+
discard_from_aftable,
|
|
52
|
+
eigenstrat_to_afs,
|
|
53
|
+
get_block_lengths,
|
|
54
|
+
is_polymorphic,
|
|
55
|
+
iter_geno_to_afs,
|
|
56
|
+
packedancestrymap_to_afs,
|
|
57
|
+
plink_to_afs,
|
|
58
|
+
read_eigenstrat,
|
|
59
|
+
read_ind,
|
|
60
|
+
read_packedancestrymap,
|
|
61
|
+
read_plink,
|
|
62
|
+
read_snp,
|
|
63
|
+
tgeno_to_afs,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
__all__ = [
|
|
67
|
+
"__version__",
|
|
68
|
+
"AfData",
|
|
69
|
+
"BlockStats",
|
|
70
|
+
"F2Blocks",
|
|
71
|
+
"F4BlockCache",
|
|
72
|
+
"F4ModelCache",
|
|
73
|
+
"QpAdmResult",
|
|
74
|
+
"QpWaveStats",
|
|
75
|
+
"afs_to_f2_blocks",
|
|
76
|
+
"anygeno_to_afs",
|
|
77
|
+
"block_covariance",
|
|
78
|
+
"detect_geno_format",
|
|
79
|
+
"discard_from_aftable",
|
|
80
|
+
"eigenstrat_to_afs",
|
|
81
|
+
"est_to_loo",
|
|
82
|
+
"f2",
|
|
83
|
+
"f2_from_geno",
|
|
84
|
+
"f3",
|
|
85
|
+
"f3_from_f2",
|
|
86
|
+
"f3_stats_from_geno",
|
|
87
|
+
"f4",
|
|
88
|
+
"f4_model_cache",
|
|
89
|
+
"f4_from_f2",
|
|
90
|
+
"f4_stats",
|
|
91
|
+
"f4_stats_from_geno",
|
|
92
|
+
"format_fstats",
|
|
93
|
+
"fst",
|
|
94
|
+
"get_block_lengths",
|
|
95
|
+
"get_f2",
|
|
96
|
+
"is_polymorphic",
|
|
97
|
+
"iter_geno_to_afs",
|
|
98
|
+
"jackknife_cov",
|
|
99
|
+
"jack_vec_stats",
|
|
100
|
+
"mats_to_aparr",
|
|
101
|
+
"mats_to_ctarr",
|
|
102
|
+
"mats_to_f2arr",
|
|
103
|
+
"qpdstat",
|
|
104
|
+
"qp3pop",
|
|
105
|
+
"qpadm",
|
|
106
|
+
"qpadm_fit",
|
|
107
|
+
"qpadm_multi",
|
|
108
|
+
"qpadm_popdrop",
|
|
109
|
+
"qpadm_rankdrop",
|
|
110
|
+
"qpadm_weights",
|
|
111
|
+
"qpwave",
|
|
112
|
+
"qpwave_f4stats",
|
|
113
|
+
"qpwave_multi",
|
|
114
|
+
"qpwave_ranktest",
|
|
115
|
+
"packedancestrymap_to_afs",
|
|
116
|
+
"plink_to_afs",
|
|
117
|
+
"read_eigenstrat",
|
|
118
|
+
"read_f2",
|
|
119
|
+
"read_ind",
|
|
120
|
+
"read_packedancestrymap",
|
|
121
|
+
"read_plink",
|
|
122
|
+
"read_snp",
|
|
123
|
+
"stats_to_loo",
|
|
124
|
+
"tgeno_to_afs",
|
|
125
|
+
"write_f2",
|
|
126
|
+
]
|