The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
Efficient simulation of genotype / phenotype data under assortative mating by generating Bahadur order-2 multivariate Bernoulli distributed random variates.
rb_dplr: generate Bahadur order-2 MVB variates with
diagonal-plus-low-rank (DPLR) correlation structuresrb_unstr: generate Bahadur order-2 MVB variates with
arbitrary correlation structuresh2_eq: compute equilibrium heritabilityrg_eq: compute equilibrium cross-mate genetic
correlationvg_eq: compute equilibrium genetic varianceam_simulate: complete univariate genotype / phenotype
simulationam_covariance_structure: compute outer-product
covariance component for AM-induced DPLR covariance structurewrite_genotypes: write genotypes as int8 or PLINK
bedread_genotypes: read genotypes back into an R
matrixam_mosaic: combine AM-induced global LD with
recombination-induced local LDkg_reference: bundled 1000 Genomes reference panelvcf_to_panel, download_1kg_panel: build
panels from real datarbahadur simulate: stream a simulation to disk without
opening Rrbahadur info: inspect an existing run and verify it is
intactrBahadur is now on CRAN:
install.packages("rBahadur")Alternatively, you can install directly from github using the
install_github function provided by the remotes
library:
remotes::install_github("border-lab/rBahadur")Here we demonstrate using rBahadur to simulate genotype
/ phenotype at equilibrium under AM: given the following parameters:
h2_0: panmictic heritabilityr: cross-mate phenotypic correlationm: number of diploid, biallelic causal variantsn: number of individuals to simulatemin_MAF: minimum minor allele frequencyset.seed(2022)
h2_0 = .5; m = 2000; n = 5000; r =.5; min_MAF=.05
## simulate genotype/phenotype data
sim_dat <- am_simulate(h2_0, r, m, n)The equilibrium variance and heritability formulas are large-locus
results. Simulations with fewer than 50 causal variants are still
allowed, but emit a warning because their realized values can differ
materially from those targets. After deciding that this finite-locus
approximation is appropriate, suppress the warning with
options(rBahadur.warn_small_m = FALSE).
We compare the target and realized allele frequencies:
## plot empirical first moments of genotypes versus expectations
afs_emp <- colMeans(sim_dat$X)/2
plot(sim_dat$AF, afs_emp)We compare the expected equilibrium heritability to that realized in simulation:
## empirical h2 vs expected equilibrium h2
(emp_h2 <- var(sim_dat$g)/var(sim_dat$y))
h2_eq(r, .5)Negative values of r correspond to disassortative
mating, which reduces genetic variance rather than inflating it:
neg <- am_simulate(h2_0, r = -.3, m, n)
var(neg$g)
vg_eq(-.3, h2_0, h2_0)For simulations too large to hold in memory, supply path
to stream genotypes to disk one batch at a time:
p <- file.path(tempdir(), "am_sim")
meta <- am_simulate(h2_0, r, m = 2e4, n = 5e3, path = p, format = "variant")
X <- read_genotypes(p)The individual and variant layouts are flat
int8, one byte per genotype with values 0, 1, and 2, so no
library beyond numpy is needed. The companion
<prefix>.meta is plain text and carries the
dimensions and the layout:
rBahadur_genotypes: 1
format: individual
n: 5000
m: 20000
dtype: int8
That is everything required to read the file:
import numpy as np
def read_meta(prefix):
meta = {}
with open(prefix + ".meta") as f:
for line in f:
key, _, value = line.partition(":")
meta[key.strip()] = value.strip()
return meta
def read_genotypes(prefix, mmap=False):
meta = read_meta(prefix)
n, m = int(meta["n"]), int(meta["m"])
if meta["format"] == "bed":
raise ValueError("bed is 2-bit packed; see the PLINK section below")
if mmap:
a = np.memmap(prefix + ".int8", dtype=np.int8, mode="r")
else:
a = np.fromfile(prefix + ".int8", dtype=np.int8)
# individual-major is already (n, m); variant-major is stored transposed
return a.reshape(n, m) if meta["format"] == "individual" else a.reshape(m, n).T
X = read_genotypes("am_sim") # (n, m), individuals by variantsThe default individual layout stores each person’s
variants contiguously, so it maps onto a C-ordered (n, m)
array with no transpose and no copy. Pass mmap=True to
leave the file on disk and page it in on demand, which is the point of
writing int8 in the first place: a 5,000 by 20,000 matrix
is 100 MB as int8 against 800 MB as doubles.
For the bed layout, use an existing PLINK reader. Note
that pandas_plink counts the opposite allele by default and
will silently return 2 - X, so pass ref="a0"
to get the dosages rBahadur actually wrote:
from pandas_plink import read_plink1_bin
G = read_plink1_bin("sim.bed", "sim.bim", "sim.fam", ref="a0", verbose=False)
X = G.values # (n, m), matches read_genotypes() in Rwrite_genotypes() has no marker annotations, so its
.bim uses documented placeholders. In contrast,
am_mosaic(..., format = "bed") preserves the reference
panel’s available chromosome, base-pair position, genetic map, marker
ID, and allele fields.
One caveat: the <prefix>.rds sidecar holding
allele frequencies, effect sizes, and phenotypes is an R object and is
not readable from Python. If the downstream analysis lives in Python,
write those out in a portable format too:
out <- am_simulate(h2_0, r, m, n, path = p, format = "individual")
write.csv(data.frame(y = out$y, g = out$g), paste0(p, "_pheno.csv"),
row.names = FALSE)
write.csv(data.frame(AF = out$AF, beta_std = out$beta_std,
beta_raw = out$beta_raw),
paste0(p, "_variants.csv"), row.names = FALSE)Reference panels should be built from phased VCFs.
vcf_to_panel() accepts unphased calls so exploratory
workflows are not blocked, but warns that the written allele order will
be treated as phase and may create artificial haplotypes and local LD.
download_1kg_panel() additionally requires
curl, zcat (from gzip), and
awk.
For generating data outside an R session, the package ships an
rbahadur executable. Put it on your path with:
ln -s $(Rscript -e "cat(rBahadur::rbahadur_cli_path())") ~/bin/rbahadurrbahadur simulate streams straight to disk, so it never
holds the genotype matrix in memory:
rbahadur simulate --h2 0.5 --r -0.3 --m 200 --n 1001 \
--out run1 --format bed --seed 7 --csvwrote run1.bed (49 Kb)
1001 individuals x 200 variants, format bed
equilibrium h2 0.4673, genetic variance 0.4385
also wrote run1_pheno.csv and run1_variants.csv
--seed makes a run reproducible, and --csv
adds _pheno.csv and _variants.csv alongside
the R-only .rds, which is what you want when the downstream
analysis is in Python. Run rbahadur --help for the full
list.
rbahadur info reports what a prefix contains and checks
the data file against its metadata, which catches a truncated
transfer:
rbahadur info run1prefix run1
format bed
dtype bed2bit
n 1001 individuals
m 200 variants
data run1.bed
size 50203 bytes actual, 50203 expected
status ok
Exit status is 0 on success, 1 for a usage
error such as a misspelled option, and 2 when a run starts
and then fails, for example when the requested disassortative
r falls outside the Bahadur feasible region. That split
lets a calling script tell a typo from a genuine modelling failure.
Developed by Richard
Border and Osman Malik.
For further details, or if you find this software useful, please cite: -
Border, R. and Malik, O.A., 2023. rBahadur: efficient
simulation of structured high-dimensional genotype data with
applications to assortative mating. BMC Bioinformatics, 24,
314. https://doi.org/10.1186/s12859-023-05442-6
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.