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
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
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 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9cbe0e423f28f1d007696ea6bdfa012acf72748b3f9667f24d844cb1773e5101
|
|
| MD5 |
d3350dcb3aed30cc3f648d879349f4b0
|
|
| BLAKE2b-256 |
3f40ba2ce53043e4cd5f5f898646180eb374daac587fa1eea7a95c4cae676d19
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8fc2fa08093981b7c17963c4eb9115043e0b7a50a0e0d18d4cd4829545ff8bd7
|
|
| MD5 |
3382e9194176b84d1d52d6b6287ceefc
|
|
| BLAKE2b-256 |
c9ff56e8430ec8a04e2aa58c5b8b5ad4b3f166c04c38413177cc30fb9b468f94
|