Skip to main content

splitiq

splitiq is a Python wrapper around SPlit.jl, a Julia package for optimal train/test splitting via support points. All computation runs in Julia through juliacall; splitiq only converts data in and out and translates errors, so its results and guarantees are those of SPlit.jl.

Installation

Install with uv:

uv add splitiq

Add the pandas extra for DataFrame input:

uv add "splitiq[pandas]"

If you are not using uv, pip works as well:

pip install splitiq            # or: pip install "splitiq[pandas]"

Python 3.12 or later is required.

Quick start

import numpy as np
import splitiq

X = np.random.default_rng(1).standard_normal((1_000, 3))
result = splitiq.datasplit(X, ratio=0.2, seed=2)

train, test = result.apply(X)          # or X[result.train_indices], X[result.test_indices]
splitiq.splitquality(X, result)        # energy distance between train and test; lower is better
splitiq.optimal_split_ratio(X[:, :2], X[:, 2])

datasplit also accepts a pandas DataFrame. category columns keep their category order; plain string/object columns are encoded using their sorted unique values as levels:

import pandas as pd

df = pd.DataFrame({'x': X[:, 0], 'g': pd.Categorical(['a', 'b', 'c'] * (len(X) // 3))})
result = splitiq.datasplit(df, ratio=0.2, seed=2)
train, test = result.apply(df)         # df.iloc[result.train_indices], df.iloc[result.test_indices]

API

Function Description
datasplit(data, ratio=0.2, *, method, kernel, bandwidth, kappa, max_iterations, tolerance, n_threads, seed) Split data into train/test sets whose distributions match closely; returns a SplitResult.
SplitResult train_indices, test_indices (0-based numpy arrays), converged, iterations, method, kernel, bandwidth, ratio; .apply(data) returns (train, test); supports train_idx, test_idx = result.
splitquality(data, result, *, kernel, bandwidth, estimator, exact_threshold, seed, n_threads) Discrepancy between the train and test rows of data; lower is better.
energydistance(x, y, *, estimator, seed, n_threads) Energy distance between two samples.
mmd(x, y, kernel='gaussian', *, bandwidth, estimator, seed, n_threads) Squared maximum mean discrepancy between two samples.
Exact(), Subsample(m, repeats=8), RandomSlices(k), RandomFeatures(D) Discrepancy estimators for energydistance/mmd/splitquality.
optimal_split_ratio(x, y, *, method='simple', degree=2) Optimal test-set fraction gamma = 1 / (sqrt(p) + 1).

method='support_points' runs the Mak & Joseph (2018) / Joseph & Vakayil (2021) optimizer; method='herding' runs greedy kernel herding. Indices are 0-based. A Julia ArgumentError surfaces as a Python ValueError; other Julia errors propagate as juliacall.JuliaError. See the docstrings under src/splitiq/ for the full argument reference, or build the API reference locally with make docs.

First call and threads

Julia does not start when you import splitiq. It starts on the first call to datasplit, splitquality, or any other function that needs it. On that first call, juliapkg installs a compatible Julia (>= 1.10, via juliaup) if none is on the PATH, instantiates SPlit.jl from git, and precompiles it. This one-time step takes a few minutes. Later starts (a new process picking up the already-installed Julia and the precompiled package) take about two seconds.

Julia runs single-threaded inside Python unless PYTHON_JULIACALL_THREADS (e.g. auto, or a number) is set in the environment before the first call. The n_threads keyword argument only limits parallelism within the threads Julia was started with; it cannot raise that count.

Versioning and releases

The splitiq version tracks the SPlit.jl version (currently 0.5.2); src/splitiq/juliapkg.json pins SPlit.jl at the git tag v<version>. Pushing a vX.Y.Z release tag builds the versioned Julia documentation and, through the PythonPublish workflow, publishes splitiq to PyPI, so both releases come from one tag. There is no separate changelog or release script for the Python package.

Development

From the splitiq/ directory:

uv sync --group dev --group docs   # install dependencies
make julia-dev                     # build .julia_dev/, developing SPlit.jl from this checkout
make test                          # run pytest against .julia_dev/
make format                        # ruff format
make lint                          # ruff check --fix
make typecheck                     # ty check
make docs                          # properdocs build --strict
make build                         # uv build

make julia-dev runs scripts/setup_julia_dev.sh, which develops SPlit.jl from the repository checkout instead of the git-pinned revision in juliapkg.json, and pins PythonCall to the version juliacall itself requires. make test runs against that project by setting PYTHON_JULIACALL_PROJECT/PYTHON_JULIACALL_EXE.

Pre-commit hooks are configured at the repository root and run from there (uvx pre-commit run -a), not from splitiq/.

References

  • Mak, S. & Joseph, V. R. (2018). Support points. Annals of Statistics, 46(6A).
  • Joseph, V. R. & Vakayil, A. (2021). SPlit: An optimal method for data splitting. Technometrics, 63(4).
  • Joseph, V. R. (2022). Optimal ratio for data splitting. Statistical Analysis and Data Mining, 15(4).
  • Chen, Y., Welling, M. & Smola, A. (2010). Super-samples from kernel herding. UAI.

This project template is generated by copier-modern-ml.

Metadata

Release files for splitiq 0.5.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for splitiq 0.5.2
File Size Uploaded
splitiq-0.5.2.tar.gz 14.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for splitiq 0.5.2
File Interpreter ABI Platform
splitiq-0.5.2-py3-none-any.whl Python 3 none any Details

Total release size: 29.8 kB

Release files / splitiq-0.5.2.tar.gz

Download URL splitiq-0.5.2.tar.gz
Size 14.2 kB
Tags Source
SHA-256 checksum
How to use checksums
7c61ebd12c01d64240d2378e9a3a27e95f2498acc54cc29162de4299524454d6
BLAKE2b-256 checksum
How to use checksums
81f86650e248874682ff1b455d81fa06c3273a105fae1f1604c488bfb104acf7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.

Transparency log

Release files / splitiq-0.5.2-py3-none-any.whl

Download URL splitiq-0.5.2-py3-none-any.whl
Size 15.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4e2a5c48c12a50feee40a627725f64af5f0d55f690669de2911cd26b6e8a018b
BLAKE2b-256 checksum
How to use checksums
c0867b43fbe45271c9a52d00ef9feff58eeb1acc0e386a923ebda37371d5a668
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.

Transparency log

Release history Release notifications | RSS feed

0.6.0

2 release files

This release

0.5.2 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page