Skip to main content

infer_sex (Python)

Pythonic port of SauersML/infer_sex. Counts heterozygous calls per chromosome region and applies a linear decision boundary on (x_autosome_het_ratio, y_genome_density) to call genetic sex. The algorithm + every numeric constant are kept byte- identical to the Rust crate.

from infer_sex import SexInferer, platform_from_bim

inferer = SexInferer(
    build="hg38",
    platform=platform_from_bim("/data/cohort.bim", build="hg38"),
)

# Pick your input — they're all type-checked and return the same shape:
result = inferer.infer_from_vcf("/data/sample.vcf.gz")
# or  inferer.infer_from_plink("/data/cohort")
# or  inferer.infer_from_records([("X", 100_000_000, True), ...])
# or  inferer.infer_from_arrays(chrom_codes, positions, is_het)

print(result.final_call)   # InferredSex.MALE / .FEMALE / .INDETERMINATE
print(result.report.composite_sex_index)

Install

pip install infer_sex

Pure Python + numpy. No Rust toolchain required.

Platform definitions

The algorithm normalises observed counts by the attempted counts on the platform — pass them in via PlatformDefinition. Two helpers compute them for you in one call:

from infer_sex import platform_from_bim, platform_from_vcf

platform = platform_from_bim("/data/cohort.bim", build="hg38")
platform = platform_from_vcf("/data/cohort.vcf.gz", build="hg38")

These walk the file once, counting autosomal rows and Y-non-PAR rows. Everything else (X, Y-PAR, MT, alt contigs) is ignored — exactly the locus set the inference algorithm uses for normalisation.

If you already know the counts (e.g. from a manifest), construct PlatformDefinition directly:

from infer_sex import PlatformDefinition

platform = PlatformDefinition(
    n_attempted_autosomes=2_000,
    n_attempted_y_nonpar=1_000,
)

Shortcuts: pass what you already know

infer_sex never touches the network. Skip build detection by passing build= directly. Use custom decision thresholds (e.g. one fit on your own labelled data) via DecisionThresholds:

from infer_sex import DecisionThresholds

inferer = SexInferer(
    build="hg38",
    platform=PlatformDefinition(...),
    thresholds=DecisionThresholds(slope=0.30, intercept=0.25),
)

Inputs

  • infer_from_vcf(path) — .vcf / .vcf.gz. Multi-sample files default to the first column with a UserWarning; pass sample= to pick by ID (str) or 0-based index (int).
  • infer_from_plink(prefix) — variant-major .bed/.bim/.fam. Pass sample= to pick a specific row of the FAM (string IID/FID or 0-based index). Reads via np.memmap; biobank-scale .beds are fine.
  • infer_from_records(iterable) — accepts (chrom, pos, is_het) triples. Useful when reading from a custom source.
  • infer_from_arrays(chrom, pos, is_het) — parallel numpy arrays; ~10× faster than infer_from_records for the same data.

Missing genotypes (./. in VCF, 0b01 in PLINK) are dropped — they don't count toward the denominator, matching the Rust crate.

Streaming API

SexInferenceAccumulator is the streaming primitive:

acc = inferer.accumulator()
for chrom, pos, is_het in my_stream:
    acc.add(chrom, pos, is_het)
# bulk path:
acc.add_batch(chrom_array, pos_array, is_het_array)
# any time:
print(acc.snapshot())       # raw counts, no classification
result = acc.finish()        # full inference; does not consume the accumulator

Results

result.final_call           # InferredSex enum
result.is_male / .is_female / .is_indeterminate
result.report.y_genome_density          # Optional[float]
result.report.x_autosome_het_ratio      # Optional[float]
result.report.composite_sex_index       # Optional[float]
result.report.auto_valid_count          # int (and many more counts)
result.report.as_dict()                  # plain dict, JSON-ready

Errors

  • InvalidPlatformCounts — the PlatformDefinition is unusable (e.g. zero autosomes).
  • ObservedExceedsAttempted — more observations than the platform claims (your platform definition doesn't match the input stream).

Both subclass InferenceError.

Cross-language guarantee

Every PAR/non-PAR coordinate, the 1e-9 epsilon, the default DecisionThresholds(slope=0.3566, intercept=0.2738), and the classification formula are kept byte-identical to src/lib.rs in this same repo. Calls match across languages — feed the same variant stream to the Rust accumulator and the Python SexInferer and you get the same InferredSex.

Metadata

Release files for infer-sex 0.1.0

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

Source distribution (sdist)

Source distribution for infer-sex 0.1.0
File Size Uploaded
infer_sex-0.1.0.tar.gz 17.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for infer-sex 0.1.0
File Interpreter ABI Platform
infer_sex-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 31.4 kB

Release files / infer_sex-0.1.0.tar.gz

Download URL infer_sex-0.1.0.tar.gz
Size 17.3 kB
Tags Source
SHA-256 checksum
How to use checksums
91f2539d178fab162425f1a3a52d86b959e5206eef1d13e10a4f9209c6ef83db
BLAKE2b-256 checksum
How to use checksums
ce3dbb412e033924fff6b1f69ee1bcdc2177906c29a371229541f525ae16f448
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.5

Release files / infer_sex-0.1.0-py3-none-any.whl

Download URL infer_sex-0.1.0-py3-none-any.whl
Size 14.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bb2a2051a26e475a6faf8e6e6158e74ec125e3c75d9e6a8299da715f090d7918
BLAKE2b-256 checksum
How to use checksums
86b462d44ad82ee71f391d786f6866edb87ad36e0ab8dae4aab3131eb30ea0a2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.5

Release history Release notifications | RSS feed

This release

0.1.0 This release

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