Skip to main content

mlsampler

A constraint-aware sampling library for reverse analysis and design of experiments.

mlsampler generates synthetic rows that satisfy constraints you declare, across continuous, integer, binary and categorical columns at the same time. Give it a sample of your data; it infers each column's type and range, and samples within them.

Installation

pip install mlsampler

HyperGridSampler additionally needs scipy:

pip install mlsampler scipy

Requires Python 3.11 or newer.

Quick start

import pandas as pd
from mlsampler import RandomSampler

train = pd.DataFrame({
    "is_active":   [1, 0, 1, 1, 0],
    "is_negative": [0, 1, 0, 0, 1],
    "score":       [10, 0, 50, 100, 5],
    "temperature": [-5.5, 20.0, 36.6, -1.2, 15.8],
    "category":    ["A", "B", "C", "D", "100"],
    "city":        ["Tokyo", "Osaka", "Nagoya", "Fukuoka", "Sapporo"],
})

sampler = RandomSampler.setup(train.values, random_state=42)

# exactly one of the two flags is on
sampler.set_constraints("multihot", cols=[0, 1], n_hot=1)
# keep temperature in a range the training data never covered
sampler.set_constraints("range", cols=[3], low=-10.0, high=40.0)
# category and city must stay a combination that actually occurs
sampler.set_constraints(
    "categories",
    cols=[4, 5],
    values=train[["category", "city"]].to_numpy(),
    strength="soft",
)

result = sampler.sample(1000)
print(pd.DataFrame(result, columns=train.columns))

Columns are addressed by integer position, not by name.

Which sampler?

RandomSampler HyperGridSampler
Purpose satisfy several constraints at once cover a continuous space evenly (DoE)
Constraints yes no
Method rejection sampling with retries Latin Hypercube + uniform grid
Needs scipy no yes

Constraint reference

Register constraints with set_constraints(name, **kwargs).

Name Effect Arguments
"sum" distributes a total across the columns cols, sum_value, method, alpha, min_used, max_used
"sumint" as sum, but partitions an integer total into whole numbers cols, sum_value, min_used, max_used
"multihot" sets exactly n_hot columns to 1, the rest to 0 cols, n_hot
"random" keeps a random subset, zeroes the others cols, min_used, max_used
"range" draws uniformly from [low, high] cols, low, high
"categories" restricts columns to allowed combinations cols, values, strength
"step" snaps onto low + k * step col, step, low, high
"stepsum" distributes a total in fixed increments cols, sum_value, lows, highs, step
callable accepts/rejects a row, or rewrites its columns cols

"step" takes col (a single integer). Every other constraint takes cols (a list). This is the one inconsistency in the API; passing cols= to "step" raises a ConstraintValidationError telling you so.

All constraints also accept rng, honoured only when n_jobs=1.

A callable receives the row after every other constraint has shaped it. Return a bool to accept or reject, or a numpy array to write into cols:

sampler.set_constraints(lambda row: float(row[3]) < 30.0, cols=[3])

Rows are dtype=object arrays, since one row mixes numbers with category strings — cast before doing arithmetic.

Reproducibility

Equal random_state under equal n_jobs produces equal output, with or without constraints.

a = RandomSampler.setup(X, random_state=42, n_jobs=1).sample(100)
b = RandomSampler.setup(X, random_state=42, n_jobs=1).sample(100)
(a == b).all()   # True

Three things to know:

  • A seeded sampler restarts its stream on each sample() call, so calling sample() twice on one sampler returns the same rows. Use a different seed, or random_state=None, for fresh draws.
  • Output is not guaranteed to match across different n_jobs values.
  • n_jobs=-1 resolves to the machine's core count, so it does not reproduce across machines with different core counts. Pass an explicit integer if you need that.

Parallel execution

n_jobs defaults to 1. Enabling parallelism only pays off when constraints reject most candidates, since starting worker processes costs more than generating a row. Measured speedup against serial:

Rejection rate n=200 n=1000 n=5000
0% 0.00x 0.22x 0.69x
80% 0.30x 0.67x 1.72x
95% 1.21x 2.15x 4.25x

Below 100 requested rows the serial path is used regardless of n_jobs.

Limitations

  • HyperGridSampler does not support constraints; set_constraints() raises NotImplementedError.
  • HyperGridSampler requires scipy.
  • Constraints are applied per row, so very large draws are bounded by Python-level iteration rather than vectorised numpy.
  • Input must not contain missing values; setup() raises on NaN/None.

Upgrading to 0.4.0

This release fixes reproducibility, which was broken whenever a constraint was registered. It contains breaking changes.

Output changes for the same seed. Constraints are now seeded from the sampler instead of drawing from fresh entropy, and one generator serves a whole sample() call instead of one per row. Rows generated by 0.3.x cannot be reproduced by 0.4.0. In exchange, random_state now actually works with constraints — before, it did not.

Change What breaks What to do
n_jobs now defaults to 1 sampling is no longer parallel by default pass n_jobs=-1 explicitly if your constraints reject most candidates
constraint arguments are now explicit a misspelled or inapplicable argument raises ConstraintValidationError instead of being ignored fix the argument — it was never taking effect
SamplerConfig.batch_size removed code passing batch_size raises TypeError drop it; nothing ever read it

Two things that used to fail silently now raise:

  • HyperGridSampler.set_constraints(...) accepted constraints and ignored them. It now raises NotImplementedError.
  • set_constraints("multihot", ..., min_used=1) and similar were accepted for constraints that cannot use them. They are now rejected at registration.

One thing that used to raise now works: categories with strength="hard" rejects and redraws instead of aborting with ConstraintViolationError, which is what makes it usable at all.

Documentation

https://jugais.github.io/randsampler/

Use cases

  • Reverse analysis — finding inputs that satisfy target conditions
  • Candidate generation for optimization
  • Design of experiments over a mixed continuous/categorical space

Metadata

Release files for mlsampler 0.4.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 mlsampler 0.4.0
File Size Uploaded
mlsampler-0.4.0.tar.gz 27.8 kB Details

Built distribution (wheel)

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

Total release size: 47.0 kB

Release files / mlsampler-0.4.0.tar.gz

Download URL mlsampler-0.4.0.tar.gz
Size 27.8 kB
Tags Source
SHA-256 checksum
How to use checksums
e965afffefbebcc89b3fff1c8cc8c1a4440caea59b1ace0b55b10f9a1b54ecdf
BLAKE2b-256 checksum
How to use checksums
f93bc736fe6763b6d0a3453d6c345154935a4c8137756a921a2aa0add0cf307b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.0.1 CPython/3.11.8

Release files / mlsampler-0.4.0-py3-none-any.whl

Download URL mlsampler-0.4.0-py3-none-any.whl
Size 19.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
373a344d7aef88fb0137a4037b00d626138c1e5dab82c18a59b3b7ee288eb5ea
BLAKE2b-256 checksum
How to use checksums
6b5ebe083ace63a16e2d6a7266be764cfbdd2de9e3adc7fa4b33a1422b76b1d0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.0.1 CPython/3.11.8

Release history Release notifications | RSS feed

0.5.1

2 release files

0.5.0

2 release files

This release

0.4.0 This release

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.1

2 release files

0.3.0

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