scikit-allel
repository·master·Indexed 43 days ago
https://github.com/cggh/scikit-allelA Python library for the exploratory analysis of large-scale genetic variation data. It provides tools for reading and converting VCF, GFF3, and FASTA files, as well as specialized data structures like GenotypeChunkedArray and GenotypeDaskArray for handling datasets that exceed memory. The library includes modules for calculating admixture statistics (Patterson f2, f3, and D), performing PCA and randomized PCA, and analyzing Hardy-Weinberg equilibrium and Mendelian inheritance.
What's inside scikit-allel
- scikit-allel is a Python package designed for the exploratory analysis of large-scale genetic variation data. It provides tools for processing and analyzing genomic datasets.
Analyze Mendelian inheritance with allel.stats.mendel
masterThe
allel.stats.mendelmodule provides tools for analyzing Mendelian inheritance patterns, specifically for identifying errors in pedigree data and performing phasing based on transmission patterns.Key functionalities include:
- Error detection: Identifying Mendelian inconsistencies using
allel.mendel_errors. - Transmission painting: Using
allel.paint_transmissionto track how alleles are passed down. - Phasing: Reconstructing haplotypes using transmission logic via
allel.phase_by_transmission,allel.phase_progeny_by_transmission, orallel.phase_parents_by_transmission.
- Error detection: Identifying Mendelian inconsistencies using
Important notice regarding scikit-allel development status
masterscikit-allel is currently in maintenance-only mode and is no longer under active development.
For new projects or those requiring better scaling, performance, and maintainability, the intended successor is sgkit (the Statistical Genetics Toolkit). While sgkit is the recommended path forward, note that it may not yet have full feature parity with scikit-allel.
Use Dask arrays for large-scale genomic data
masterFor datasets that exceed available memory,
scikit-allelprovides Dask-backed array implementations. These classes allow you to work with large genomic datasets by leveraging Dask's lazy evaluation and parallel computing capabilities. Instead of loading entire arrays into RAM, these objects represent chunks of data that are processed on demand.Supported Dask-backed array types include:
GenotypeDaskArray: For genotype data.HaplotypeDaskArray: For haplotype data.AlleleCountsDaskArray: For allele counts data.
Install scikit-allel via conda
masterYou can install pre-built binaries for Windows, Mac, and Linux using
conda. This method installsscikit-allelalong with all its necessary dependencies.$ conda install -c conda-forge scikit-allelInstall scikit-allel via pip
masterIf you have a C compiler on your system, you can install
scikit-allelusingpip.By default, this installs
scikit-allelwith minimal dependencies (numpy,cython, anddask).To install
scikit-allelwith all optional third-party dependencies (includingscipy,matplotlib,seaborn,pandas,scikit-learn,h5py, andzarr), use the[full]extra.# Minimal installation $ pip install scikit-allel # Full installation with all optional dependencies $ pip install scikit-allel[full]Compare different genotype array storage classes
masterscikit-allel provides several array classes for storing genotype data, each with different memory and performance characteristics:
allel.model.GenotypeArray: A contiguous NumPy-based array. It is fast for computations but uses more memory.allel.bcolz.GenotypeCArray: A compressed array using thebcolzformat. It significantly reduces memory footprint.allel.bcolz.GenotypeCArray(withrootdir): A compressed, persistent array that can be stored on disk.GenotypeArraywith a.mask: An array that includes a boolean mask to represent missing data.to_sparse(format='csr'): Converts aGenotypeArrayinto a SciPy sparse matrix (e.g., CSR format) for memory efficiency when data is sparse.
Use
nbytesfor NumPy arrays orcbytesforbcolzarrays to check memory usage.# Contiguous array (numpy) g = allel.model.GenotypeArray(data, copy=False) # Compressed array (bcolz) gc = allel.bcolz.GenotypeCArray(data) # Compressed persistent array (bcolz) import tempfile rootdir = tempfile.mkdtemp() gcp = allel.bcolz.GenotypeCArray(data, rootdir=rootdir, mode='w') # Arrays with mask gm = g.copy() gm.mask = mask # Sparse array (scipy) m = g.to_sparse(format='csr')Handle genomic gaps in selection statistics
masterLarge gaps between consecutive variants can introduce artifacts in selection statistics.
When using
allel.stats.ihs, you can control how gaps are treated using:max_gap: Sets the maximum allowed distance between variants.clip_gap: Sets the distance to which gaps are clipped.is_accessible: Provides a mask to adjust scores based on genomic accessibility, which can mitigate the impact of gaps in non-accessible regions.
Compare GenotypeArray and GenotypeCArray for FST calculations
masterIn
scikit-allel, $F_{ST}$ calculations can be performed using eitherallel.GenotypeArrayorallel.GenotypeCArray.GenotypeArrayis the standard representation for genotype data.GenotypeCArrayis a compressed representation.
Profiling indicates that
weir_cockerham_fstcan be called directly with aGenotypeCArray, and the resulting components (a,b,c) are equivalent to those produced by aGenotypeArray.# Using GenotypeArray g = allel.GenotypeArray(data) a, b, c = allel.stats.weir_cockerham_fst(g, subpops) # Using GenotypeCArray gc = allel.GenotypeCArray(data) ac, bc, cc = allel.stats.weir_cockerham_fst(gc, subpops) # Results are equivalent import numpy as np assert np.array_equal(a, ac)Map alleles in a GenotypeArray using Dask for parallel processing
masterWhen working with large datasets that exceed memory, you can perform allele mapping in parallel using
dask.array. SinceGenotypeArray.map_allelesis a NumPy-based operation, you can usedask.array.map_blocksto apply the mapping to chunks of the data.To use this pattern, you must ensure that the
mappingarray is also chunked such that its first dimension aligns with the chunks of theGenotypeArray.Implementation Pattern:
- Convert the
GenotypeArrayto a Dask array (gd). - Convert the
mappingarray to a Dask array (md). - Define a helper function
f(block, bmapping)that wraps theGenotypeArrayconstructor and calls.map_alleles()on the block. - Use
da.map_blocksto apply the function across the chunks.
import allel import dask.array as da import numpy as np # Setup GenotypeArray and mapping g = allel.GenotypeArray(data, dtype='i1') mapping = np.array(mapping_data, dtype='i1') # Create Dask arrays chunks_dim0 = 2 gd = da.from_array(g, chunks=(chunks_dim0, 2, None)) md = da.from_array(mapping, chunks=(chunks_dim0, None)) # Mapping function for blocks def f(block, bmapping): return allel.GenotypeArray(block).map_alleles(bmapping[:, 0, :]) # Apply mapping in parallel gmapped1 = da.map_blocks(f, gd, md[:, None, :], chunks=gd.chunks) # Compute result back to GenotypeArray actual = allel.GenotypeArray(gmapped1.compute())- Convert the
Parallelize computations with Dask and Blosc
masterWhen using
GenotypeDaskArraywithbcolzdata, performance is influenced by two levels of threading:- Blosc threads: Controlled via
bcolz.blosc_set_nthreads(n). This manages the decompression parallelism. - Dask workers: Controlled via the
num_workersargument in.compute(). This manages the task-level parallelism.
To optimize performance, you should experiment with different combinations of these two thread counts. For example, using 4 Blosc threads and 4 Dask workers can often result in a total wall time that is less than the sum of decompression and computation times, as Dask can overlap these tasks.
import bcolz # Set Blosc decompression threads bcolz.blosc_set_nthreads(4) # Execute Dask computation with a specific number of workers # This allows Dask to parallelize the workload across 'm' workers result = gd.max().compute(num_workers=4)- Blosc threads: Controlled via
Phase parents using allel.phase_parents_by_transmission
masterUseallel.phase_parents_by_transmissionto phase the parental genotypes based on the transmission patterns observed in their offspring.