Skip to main content

High-dimensional Undirected Mixed graph Learning in PYthon

Project description

HUMLPY: High-dimensional Undirected Mixed graph Learning in PYthon

Python 3.10+ License: MIT Documentation Code style: ruff Tests

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:

  1. 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)
  2. Fitting the graphical lasso over a log-spaced regularisation path.

  3. Selecting the sparsity level that minimizes the extended BIC (eBIC).

  4. Returning the estimated precision matrix and a UGRAPH of 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

License

MIT License — see LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

humlpy-0.1.0.tar.gz (34.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

humlpy-0.1.0-py3-none-any.whl (24.2 kB view details)

Uploaded Python 3

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

Hashes for humlpy-0.1.0.tar.gz
Algorithm Hash digest
SHA256 6f22d25b62efec6617ba934dd2829ca0a2c8f59427ae3806d354b7b42cef0bea
MD5 879c58cf491011955ff694cbc9043b97
BLAKE2b-256 4d66f3354db9955b0c91e1205e47d83c8e7625b336a5896b561d7b2d616777d9

See more details on using hashes here.

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

Hashes for humlpy-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b556a89f580b33adca5806ff8877c20ccd7b32c9b1957e33aac5a2f28c54b091
MD5 c0698cd6bf8c2ed905ce0cc903b0bc38
BLAKE2b-256 6fc3b183191b1005c32d207ea2bc7eb9cae88b42b532b799ad971d47301c6f4c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page