MethylUtils¶
Scope¶
methylutils is the mathematical spine of the repository. The core implementations live in:
methyl_utils/core/centroid_builder.pymethyl_utils/core/distribution_views.pymethyl_utils/methyl_centroid_pair.pymethyl_utils/statistical_tests.pymethyl_utils/ecdf_classifier.py
Those modules define the empirical-distribution view used by centroid comparison, DMP detection, and ECDF classification. They also expose several auxiliary or legacy methods, especially beta-based distances, that remain available as optional utilities.
Implemented Method Inventory¶
| Area | Main code path | Status in this book |
|---|---|---|
| centroid sufficient statistics | core/centroid_builder.py |
principled |
| ECDF reconstruction from histograms | core/distribution_views.py |
principled numerical representation |
| continuous overlap integral | statistical_tests.py |
approximate numerical integration |
| KS testing on reconstructed ECDFs | statistical_tests.py |
asymptotic and grid-based |
| Mann-Whitney from binned counts | statistical_tests.py |
approximate because it reconstructs rank information from histograms |
| Storey q-values | statistical_tests.py |
principled, with standard tuning caveats |
| DerSimonian-Laird style heterogeneity | statistical_tests.py |
principled method-of-moments adaptation |
| canonical biological effect size | statistical_tests.py |
heuristic ranking score |
| ECDFClassifier | ecdf_classifier.py |
principled scoring rule plus heuristic stabilizers |
| beta distances and overlaps | metrics_core.py |
auxiliary; not the main detector-classifier path |
Centroid Sufficient Statistics¶
For each locus $i$, the builder stores per-sample methylation fractions $x_{si}$ together with aggregate statistics:
where $N_i$ is the number of samples contributing to that locus and $\varepsilon$ is a small numerical floor.
The centroid builder also stores count-level summaries:
which are later reused by the heterogeneity calculation. Finally, each locus accumulates histogram counts $c_{ib}$ over shared bin edges ${e_b}$, producing the binned_stats object that drives both ECDF reconstruction and histogram-based testing.
ECDF Reconstruction¶
The code constructs a cumulative distribution at bin edges by normalizing cumulative bin counts:
ECDFView then interpolates these edge values with a monotone PCHIP spline [fritsch1980]. The resulting representation supplies:
- a continuous cumulative distribution $\tilde F_i(x)$,
- a continuous density proxy $\tilde f_i(x) = \max(\partial_x \tilde F_i(x), \varepsilon)$, and
- numerically stable means and variances via the stored sufficient statistics.
This is an empirical-distribution model, not a beta or Gaussian fit. That distinction is central to the detector-classifier path.
Two-Sample Comparison¶
KS Statistic on Reconstructed ECDFs¶
For aligned centroid pairs, the code evaluates the two-sample Kolmogorov-Smirnov statistic
Implementation detail matters here: the supremum is approximated on a uniform grid rather than computed analytically, and the $p$-value is obtained from the large-sample Smirnov distribution [@kolmogorov1933; @feller1948] using the harmonic mean effective sample size
This is a reasonable screening approximation, but it is not an exact finite-sample KS test on raw observations.
Mann-Whitney from Histogram Counts¶
The repository also implements a vectorized Mann-Whitney calculation directly from centroid histograms. Let $c^{(1)}{ib}$ and $c^{(2)}$ be the two groups' bin counts at locus $i$. The code reconstructs the $U$ statistic as
This is followed by the usual normal approximation,
This is a useful heterogeneity diagnostic, but it should be described as a method-of-moments adaptation to stored centroid summaries, not as a full random-effects model fit.
Continuous Overlap¶
Once densities have been reconstructed, the code measures shared support through
Numerically, the integral is evaluated on a dense grid after each density is renormalized by trapezoidal integration. This makes the overlap robust to small interpolation drift, but it remains a grid approximation.
Multiple Testing and p-Value Aggregation¶
For genome-wide DMP screening, storey_qvalues() estimates the null fraction $\pi_0$ across a grid of $\lambda$ values and then computes monotone q-values [storey2003]:
The same module also provides Fisher [fisher1925] and Stouffer [stouffer1949] style p-value combination utilities. Those are not central to the detector itself, but downstream packages reuse them conceptually for gene-level aggregation.
Canonical Biological Effect Size¶
The repository separates statistical significance from a biological ranking score. The implemented canonical effect size is
An optional mean-level weight $g(\bar\mu_i)$ can be applied, with the code supporting square-root, linear, saturating, and boundary-threshold variants.
This score is useful operationally, but it is not a test statistic, likelihood ratio, or posterior quantity. It is a deliberately engineered ranking rule. Publication text should therefore describe it as a heuristic biological prioritization score.
ECDFClassifier¶
The classifier in ecdf_classifier.py turns the centroid histograms into per-class densities and scores a sample $x = (x_1,\dots,x_p)$ via a weighted mean log-density:
The class probabilities are then computed by temperature-scaled softmax:
where $n_{\text{effective}} = (\sum_i w_i)^2 / \sum_i w_i^2$ is the inverse-Simpson effective number of weighted loci.
Two stabilizers are important because they materially affect behavior:
- log-densities are floored before averaging, so extremely small density values cannot dominate the score, and
- unavailable loci are removed from the denominator by setting their effective weights to zero.
The result is a practical Naive Bayes style classifier [domingos1997], but it is not a fully calibrated generative posterior unless the independence and density assumptions actually hold. Optional Platt scaling [platt1999] may further recalibrate the binary probabilities after the ECDF score has been computed.
Auxiliary Beta-Based Metrics¶
metrics_core.py still contains exact beta divergences, beta overlap surrogates, and moment calculations. A legacy beta-comparator module (methyl_utils/comparison.py) was removed from the active package tree; beta-distance utilities in metrics_core.py remain for auxiliary analysis only. They are not the main production path for DMP detection plus classification and are not used by the active detector/classifier runtime flow. In publication text, beta distances should therefore be described as an auxiliary branch of the repository, not as the canonical detector-classifier model.