Skip to main content

splitiq

splitiq is a Python wrapper around SPlit.jl, a Julia package for distribution-preserving subset selection on tabular data and embeddings: optimal train/test splits, k-fold multiplets, and training-data selection by support points, kernel herding, twinning, and kernel thinning. 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, start, delta=0.5, compress='auto', weights, reference, reference_weights, standardize=True) Split data into train/test sets whose distributions match closely; returns a SplitResult.
select_rows(data, n, *, method, kernel, bandwidth, kappa, max_iterations, tolerance, n_threads, seed, start, delta=0.5, compress='auto', weights, reference, reference_weights, standardize=True) The indices of the n rows of data the splitter chose, without building a train/test partition.
SplitResult train_indices, test_indices (0-based numpy arrays), converged, iterations, method, kernel, bandwidth, ratio, selected ('test'/'train', the side holding the chosen rows); .apply(data) returns (train, test); supports train_idx, test_idx = result.
multiplet(data, k, *, strategy='sequential', method='twinning', kernel, bandwidth, kappa, max_iterations, tolerance, n_threads, seed, start, delta=0.5, compress='auto', weights, reference, reference_weights, standardize=True) Split data into k distribution-balanced folds under strategy ('sequential', 'halving', or 'single'); returns a list of index arrays.
splitquality(data, result, *, kernel, bandwidth, estimator, exact_threshold, seed, n_threads, standardize=True) Discrepancy between the train and test rows of data; lower is better.
compare(data, methods, *, ratio=0.2, kernel='energy', bandwidth, seed, n_threads, weights, reference, reference_weights, standardize=True) Run datasplit with each method spec in methods (a name or a {'method': ..., ...} mapping) and score every split under the scoring kernel; returns a SplitComparison.
SplitComparison results, qualities (index-aligned with methods), scoring kernel; .best() returns the (index, result) pair with the lowest quality.
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 (2022) optimizer; method='herding' runs greedy kernel herding; method='twinning' runs sequential nearest-neighbor twinning (Vakayil & Joseph, 2022); method='kernel_thinning' runs generalized kernel thinning (Dwivedi & Mackey, 2022/2024). 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. examples/ has two worked scripts: LLM training-data selection and time-series window selection.

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, together with PYTHON_JULIACALL_HANDLE_SIGNALS=yes, which juliacall requires for more than one thread (it makes Ctrl-C stop raising KeyboardInterrupt in that process). The n_threads keyword argument only limits parallelism within the threads Julia was started with; it cannot raise that count, and method='twinning' rejects it. Results do not depend on the thread count. juliacall is not thread-safe on the Python side, so keep splitiq calls on one Python thread and let Julia parallelize inside the call; for several processes, start workers with spawn and give each a large batch, since every process boots its own Julia. The Python page of the SPlit.jl documentation has the full guide.

Versioning and releases

The splitiq version tracks the SPlit.jl version (currently 0.6.0); 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

  • Joseph, V. R., & Vakayil, A. (2022). SPlit: An Optimal Method for Data Splitting. Technometrics, 64(2), 166-176. DOI
  • Mak, S., & Joseph, V. R. (2018). Support points. The Annals of Statistics, 46(6A), 2562-2592.
  • Joseph, V. R. (2022). Optimal Ratio for Data Splitting. Statistical Analysis and Data Mining: The ASA Data Science Journal, 15(4), 531-538.
  • Gretton, A., Borgwardt, K. M., Rasch, M. J., Schölkopf, B., & Smola, A. (2012). A Kernel Two-Sample Test. Journal of Machine Learning Research, 13, 723-773.
  • Chen, Y., Welling, M., & Smola, A. (2010). Super-Samples from Kernel Herding. UAI, 109-116.
  • Rahimi, A., & Recht, B. (2007). Random Features for Large-Scale Kernel Machines. NIPS, 20.
  • Vakayil, A., & Joseph, V. R. (2022). Data Twinning. Statistical Analysis and Data Mining, 15(5), 598-610.
  • Dwivedi, R., & Mackey, L. (2022). Generalized Kernel Thinning. ICLR.
  • Dwivedi, R., & Mackey, L. (2024). Kernel Thinning. Journal of Machine Learning Research, 25(152), 1-77.
  • Shetty, A., Dwivedi, R., & Mackey, L. (2022). Distribution Compression in Near-Linear Time. ICLR.

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

Metadata

Release files for splitiq 0.6.0

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.6.0
File Size Uploaded
splitiq-0.6.0.tar.gz 23.5 kB Details

Built distribution (wheel)

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

Total release size: 51.3 kB

Release files / splitiq-0.6.0.tar.gz

Download URL splitiq-0.6.0.tar.gz
Size 23.5 kB
Tags Source
SHA-256 checksum
How to use checksums
e48eaa6d2cf24db0ee6a155b6d51e8c56a14fc3da9b873e626bc595a08fcbe3c
BLAKE2b-256 checksum
How to use checksums
e1a28107e7492f1ef008f8dd0a27f9f305a1defedb30e903710fa61057f5c65b
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 5, 2026.

Transparency log

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

Download URL splitiq-0.6.0-py3-none-any.whl
Size 27.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ddf2bd4a5a9030a9d33a17245fc88f285386592204a654090f104328f7d86d5d
BLAKE2b-256 checksum
How to use checksums
22bd310b6a8bda3700947de25c7567da378b0f94d8b5158f58235065a17bcff2
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 5, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.6.0 This release

2 release files

0.5.2

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