Skip to main content

This package provides an implementation of the Mixed PC algorithm for learning causal graphical models from data with mixed variable types.

Project description

mixpc: Mixed PC Algorithm for Causal Discovery

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

mixpc is a Python library for learning causal graphical models from data with mixed variable types (continuous and ordinal). It implements the PC algorithm with the PC-stable skeleton discovery variant (Colombo & Maathuis 2014) and three v-structure orientation strategies from Ramsey et al. (2016).


Features

  • PC-stable skeleton discovery — deterministic edge removal order, independent of variable ordering.
  • Three orientation strategies — conservative, majority, and PC-Max v-structure rules.
  • Mixed data support — automatic dispatch to the right correlation measure per variable pair:
    • Both continuous → nonparanormal Spearman sin-transform (Liu et al. 2009)
    • Both ordinal → polychoric MLE (Brent or Newton-Fisher solver)
    • Mixed → ad-hoc polyserial correlation
  • Prior knowledge — required/forbidden edges, required/forbidden directions, and partial temporal layering (e.g. production-line stations) integrated into all three PC phases.
  • Full Meek rule application — R1–R4 applied to maximally orient remaining undirected edges.

Installation

pip install mixpc

From source

git clone https://github.com/konstantingoe/mixed-pc.git
cd mixed-pc
pip install -e .

Development installation

git clone https://github.com/konstantingoe/mixed-pc.git
cd mixed-pc
make sync-venv

make sync-venv creates a virtual environment, installs all pinned dev dependencies via uv pip sync, and installs the package in editable mode.


Quick Start

Continuous data (Nonparanormal Fisher Z test)

import numpy as np
from mixpc import PC

rng = np.random.default_rng(42)
n = 2000

# Ground truth: X0 -> X2 <- X1, X2 -> X3
x0 = rng.normal(size=(n, 1))
x1 = rng.normal(size=(n, 1))
x2 = x0 + x1 + 0.5 * rng.normal(size=(n, 1))
x3 = x2 + 0.3 * rng.normal(size=(n, 1))

data = {"X0": x0, "X1": x1, "X2": x2, "X3": x3}

pc = PC(alpha=0.05)
pdag = pc.learn_graph(data, v_structure_rule="conservative")

print("Directed edges:", pdag.dir_edges)
# → [('X0', 'X2'), ('X1', 'X2'), ('X2', 'X3')]

Mixed data (continuous + ordinal)

import numpy as np
from mixpc import PC, MixedFisherZ

rng = np.random.default_rng(0)
n = 3000

x0 = rng.normal(size=(n, 1))
x1 = rng.normal(size=(n, 1))
x2 = x0 + x1 + 0.5 * rng.normal(size=(n, 1))

# X3 is ordinal (5 categories)
quantiles = np.percentile(x2, [20, 40, 60, 80])
x3 = np.searchsorted(quantiles, x2).reshape(n, 1).astype(float)

data = {"X0": x0, "X1": x1, "X2": x2, "X3": x3}

pc = PC(alpha=0.05, test=MixedFisherZ)
pdag = pc.learn_graph(data, v_structure_rule="majority")

print("Directed edges:", pdag.dir_edges)
# → [('X0', 'X2'), ('X1', 'X2'), ('X2', 'X3')]

Orientation strategies

Pass v_structure_rule to learn_graph:

Strategy Behaviour
"conservative" Orient as v-structure only if all separating sets exclude the middle node
"majority" Orient if majority of separating sets exclude the middle node
"pc-max" Orient based on the highest p-value across separating sets

Prior knowledge

Encode domain constraints with PriorKnowledge and pass it to learn_graph. All five hint types compose: required/forbidden edges, required/forbidden directions, and a partial temporal layering.

from mixpc import PC, PriorKnowledge

# Production-line example: three stations, intra-station ordering unknown
prior = PriorKnowledge(
    layering=[["X0", "X1"], ["X2"], ["X3"]],   # X0,X1 precede X2 precedes X3
    forbidden_directions=[("X3", "X2")],       # explicit override (redundant with layering here)
    required_edges=[("X0", "X2")],             # never tested for removal
)

pc = PC(alpha=0.05)
pdag = pc.learn_graph(data, v_structure_rule="majority", prior_knowledge=prior)

Layering is consulted in all three PC phases: it prunes conditioning sets during skeleton discovery, blocks impossible v-structures, and propagates orientations through the Meek rules.


Project Structure

.
├── mixpc/
│   ├── __init__.py
│   ├── pc_algorithm.py
│   ├── independence_tests.py
│   ├── correlations.py
│   ├── prior_knowledge.py
│   ├── graphs.py
│   └── py.typed
├── tests/
├── docs/
├── pyproject.toml
├── Makefile
├── mkdocs.yml
└── .pre-commit-config.yaml

Testing

make test       # plain pytest
make coverage   # pytest with coverage + missing-line report

Development

Managing dependencies

make requirements        # re-pin without upgrading existing deps
make update-requirements # re-pin and upgrade all deps
make sync-venv           # apply the lock files to the venv

Pre-commit hooks

pre-commit install          # enable hooks (run automatically on git commit/push)
pre-commit run --all-files  # run all hooks manually

Linting and type checking

ruff check mixpc/
mypy mixpc/

Documentation

source venv_mixed-pc/bin/activate
mkdocs serve   # live preview at http://127.0.0.1:8000
mkdocs build   # static site in site/

Deploy to GitHub Pages

mike deploy --push --update-aliases 0.1.0 latest
mike set-default --push latest   # first time only

References

  • Spirtes, P., Glymour, C. & Scheines, R. (2000). Causation, Prediction, and Search. MIT Press.
  • Colombo, D. & Maathuis, M.H. (2014). Order-independent constraint-based causal structure learning. JMLR 15, 3741–3782.
  • Ramsey, J., Zhang, J. & Spirtes, P. (2016). Adjacency-faithfulness and conservative causal inference. UAI.
  • Liu, H., Lafferty, J. & Wasserman, L. (2009). The nonparanormal. JMLR 10, 2295–2328.
  • Göbler, K., Drton, M., Mukherjee, S. & Miloschewski, A. (2024). High-dimensional undirected graphical models for arbitrary mixed data. Electronic Journal of Statistics 18(1). doi:10.1214/24-EJS2254.

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

mixpc-0.1.0.tar.gz (44.5 kB view details)

Uploaded Source

Built Distribution

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

mixpc-0.1.0-py3-none-any.whl (28.6 kB view details)

Uploaded Python 3

File details

Details for the file mixpc-0.1.0.tar.gz.

File metadata

  • Download URL: mixpc-0.1.0.tar.gz
  • Upload date:
  • Size: 44.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.14

File hashes

Hashes for mixpc-0.1.0.tar.gz
Algorithm Hash digest
SHA256 9cbe0e423f28f1d007696ea6bdfa012acf72748b3f9667f24d844cb1773e5101
MD5 d3350dcb3aed30cc3f648d879349f4b0
BLAKE2b-256 3f40ba2ce53043e4cd5f5f898646180eb374daac587fa1eea7a95c4cae676d19

See more details on using hashes here.

File details

Details for the file mixpc-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: mixpc-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 28.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.14

File hashes

Hashes for mixpc-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8fc2fa08093981b7c17963c4eb9115043e0b7a50a0e0d18d4cd4829545ff8bd7
MD5 3382e9194176b84d1d52d6b6287ceefc
BLAKE2b-256 c9ff56e8430ec8a04e2aa58c5b8b5ad4b3f166c04c38413177cc30fb9b468f94

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