High-dimensional Undirected Mixed graph Learning in PYthon
Project description
HUMLPY: High-dimensional Undirected Mixed graph Learning in PYthon
humlpy (High-dimensional Undirected Mixed graph Learning in PYthon) is a Python package for learning sparse undirected graphical models from arbitrary mixed data — any combination of continuous and ordinal variables. It is built upon the hume R package and implements the methodology developed in:
Göbler, K., Drton, M., Mukherjee, S. and Miloschewski, A. (2024). High-dimensional undirected graphical models for arbitrary mixed data. Electronic Journal of Statistics, 18(1), 2339–2404. https://doi.org/10.1214/24-EJS2254
Table of Contents
Overview
Given a high-dimensional dataset with continuous and/or ordinal variables, humlpy estimates an undirected graph by:
-
Estimating a latent correlation matrix using pair-type-specific, rank-based estimators:
- continuous – continuous: Spearman sine-transform $\hat{\sigma} = 2\sin\bigl(\tfrac{\pi}{6}\hat{\rho}_S\bigr)$
- continuous – ordinal: ad-hoc polyserial correlation
(
PolyserialCorrelation) - ordinal – ordinal: maximum-likelihood polychoric correlation
(
PolychoricCorrelation)
-
Fitting the graphical lasso over a log-spaced regularisation path.
-
Selecting the sparsity level that minimizes the extended BIC (eBIC).
-
Returning the estimated precision matrix and a
UGRAPHof the conditional independence structure.
The design mirrors sklearn.covariance.GraphicalLassoCV and integrates naturally
into a scikit-learn-style workflow (fit returns self; fitted attributes carry a
trailing underscore).
Installation
From source
pip install humlpy
Development installation
git clone https://github.com/konstantingoe/mixed-gm.git
cd mixed-gm
pip install -e ".[dev]"
Or using Make:
make sync-venv
Quick Start
Generate latent continuous data from a sparse nonparanormal model, binarize the first half of the columns via a probit transform, then fit the mixed graphical model and evaluate against the known truth.
import numpy as np
import pandas as pd
from scipy import stats
from humlpy import MixedGraphicalLasso
rng = np.random.default_rng(0)
n, d = 400, 20
# --- Sparse precision matrix ------------------------------------------------
# Identity base, signal on 12 random off-diagonal pairs, diagonal dominance
# ensures positive definiteness.
precision = np.eye(d)
pairs = [(i, j) for i in range(d) for j in range(i + 1, d)]
true_edges = set()
for idx in rng.choice(len(pairs), size=12, replace=False):
i, j = pairs[idx]
precision[i, j] = precision[j, i] = 0.5
true_edges.add(frozenset((f"x{i}", f"x{j}")))
np.fill_diagonal(precision, np.abs(precision).sum(axis=1) + 0.1)
# --- Latent multivariate normal data ----------------------------------------
cov = np.linalg.inv(precision)
X = rng.multivariate_normal(np.zeros(d), cov, size=n)
X = np.sign(X) * np.power(np.abs(X), 1.5) # nonparanormal transform
# --- Binarise first half of columns (probit / quantile transform) -----------
# Mirrors the R idiom: data[,i] <- qbinom(pnorm(scale(X[,i])), size=1, prob=p)
n_bin = d // 2
p_bin = rng.uniform(0.4, 0.6, size=n_bin)
data = pd.DataFrame(X, columns=[f"x{i}" for i in range(d)])
for i in range(n_bin):
u = stats.norm.cdf(stats.zscore(X[:, i]))
data.iloc[:, i] = stats.binom.ppf(u, n=1, p=p_bin[i])
# --- Fit the mixed graphical model ------------------------------------------
mgl = MixedGraphicalLasso().fit(data)
print(f"Selected alpha: {mgl.alpha_:.4f}")
print(f"Number of edges: {mgl.n_edges_}")
# --- Evaluation -------------------------------------------------------------
recovered = {frozenset(e) for e in mgl.graph_.edges}
tp = len(true_edges & recovered)
tpr = tp / len(true_edges)
fpr = (len(recovered) - tp) / (d * (d - 1) // 2 - len(true_edges))
print(f"TPR: {tpr:.2f} FPR: {fpr:.2f}")
Visualising the estimated graph
mgl.graph_.show()
API
Core classes
MixedGraphicalLasso
Full estimation pipeline: correlation matrix → glasso path → eBIC selection →
precision matrix + UGRAPH.
MixedGraphicalLasso(
n_lambdas=50, # length of the regularisation path
ebic_gamma=0.1, # eBIC penalty: 0 = standard BIC, higher = sparser
n_levels_threshold=20, # variables with fewer unique values treated as ordinal
)
| Fitted attribute | Description |
|---|---|
precision_matrix_ |
Estimated precision matrix (partial correlations on off-diagonal) as pd.DataFrame |
correlation_matrix_ |
Latent correlation matrix as pd.DataFrame |
graph_ |
Estimated conditional independence graph as UGRAPH |
alpha_ |
Selected regularisation parameter |
ebic_scores_ |
Full eBIC array along the path |
singular_ |
True if the correlation matrix required PD projection |
feature_names_ |
List of variable names |
n_edges_ |
Number of edges (raises RuntimeError if not fitted) |
SampleCorrelation
Estimates the latent correlation matrix only, without fitting the graphical model. Useful when you want to inspect or pre-process the correlation matrix before running your own penalized estimator.
sc = SampleCorrelation(n_levels_threshold=20).fit(data)
print(sc.correlation_matrix_)
Model selection
omega_select(precision_path, lambda_path, n, s, *, gamma=0.1)
Select the best precision matrix from a pre-computed glasso path using eBIC.
Returns (selected_omega, selected_alpha, ebic_scores).
Graph classes
| Class | Description |
|---|---|
UGRAPH |
Undirected graph — the output type of MixedGraphicalLasso |
UGRAPH exposes: nodes, edges, num_nodes,
num_edges, adjacency_matrix, from_pandas_adjacency(), to_networkx(),
remove_edge(), remove_node(), copy().
Correlation functions
| Function / Class | Description |
|---|---|
PolychoricCorrelation |
MLE polychoric correlation for ordinal–ordinal pairs |
PolyserialCorrelation |
Ad-hoc polyserial correlation for mixed pairs |
spearman(x, y) |
Spearman's ρ |
npn_pearson(x, y) |
Nonparanormal Pearson correlation |
f_hat(x) |
Nonparanormal transformation |
Legacy functions
The original function-based API is preserved for backward compatibility:
from humlpy import mixed_graph_nonpara, mixed_graph_gauss
result = mixed_graph_nonpara(data, param=0.1)
# result.precision_matrix, result.adjacency_matrix,
# result.n_edges, result.max_degree, ...
File Structure
mixed-gm/
├── humlpy/
│ ├── __init__.py # public API and package docstring
│ ├── estimation.py # SampleCorrelation, MixedGraphicalLasso, omega_select
│ ├── correlation.py # PolychoricCorrelation, PolyserialCorrelation, …
│ └── graphs.py # UGRAPH
├── tests/
│ ├── test_estimation.py # tests for estimation module
│ ├── test_correlation.py # tests for correlation module
│ └── test_graphs.py # tests for graph classes
├── docs/
│ ├── index.md # documentation home page
│ └── reference.md # API reference (mkdocstrings)
├── pyproject.toml
├── mkdocs.yml
├── Makefile
└── VERSION
Testing
pytest tests/ -v
With coverage report:
pytest tests/ --cov=humlpy --cov-report=html
Or via Make:
make test
Development
Pre-commit hooks
pre-commit install # enable hooks in the current venv
pre-commit run --all-files # run all hooks manually
Building the documentation locally
mkdocs serve # live preview at http://127.0.0.1:8000
mkdocs build # static site in site/
Linting and type checking
ruff check humlpy/ # linting
mypy humlpy/ # static type checking
References
-
Göbler, K., Drton, M., Mukherjee, S. and Miloschewski, A. (2024). High-dimensional undirected graphical models for arbitrary mixed data. Electronic Journal of Statistics, 18(1), 2339–2404. https://doi.org/10.1214/24-EJS2254
-
Foygel, R. and Drton, M. (2010). Extended Bayesian Information Criteria for Gaussian Graphical Models. Advances in Neural Information Processing Systems, 23, 604–612.
-
Liu, H., Lafferty, J. and Wasserman, L. (2009). The nonparanormal: Semi-parametric estimation of high dimensional undirected graphs. Journal of Machine Learning Research, 10(80), 2295–2328.
Authors
- Konstantin Göbler (author & maintainer)
- Stephan Haug (maintainer)
License
MIT License — see LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file humlpy-0.1.0.tar.gz.
File metadata
- Download URL: humlpy-0.1.0.tar.gz
- Upload date:
- Size: 34.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6f22d25b62efec6617ba934dd2829ca0a2c8f59427ae3806d354b7b42cef0bea
|
|
| MD5 |
879c58cf491011955ff694cbc9043b97
|
|
| BLAKE2b-256 |
4d66f3354db9955b0c91e1205e47d83c8e7625b336a5896b561d7b2d616777d9
|
File details
Details for the file humlpy-0.1.0-py3-none-any.whl.
File metadata
- Download URL: humlpy-0.1.0-py3-none-any.whl
- Upload date:
- Size: 24.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b556a89f580b33adca5806ff8877c20ccd7b32c9b1957e33aac5a2f28c54b091
|
|
| MD5 |
c0698cd6bf8c2ed905ce0cc903b0bc38
|
|
| BLAKE2b-256 |
6fc3b183191b1005c32d207ea2bc7eb9cae88b42b532b799ad971d47301c6f4c
|