Ruddy
Ruddy is a Python library for statistical exploratory data analysis. It works on tables and on numerical feature spaces such as embeddings or descriptor matrices, as long as each row belongs to an identifiable observation. Results come back as Polars tables that carry sample counts, diagnostics and the parameters used, so you can filter them, export them or plot them.
Ruddy doesn't know about any particular domain and doesn't compute features. You bring the data or the representation, and Ruddy analyzes it. It also has no plotting code, but you can use your prefered library for visualizations. See example notebooks for more comprehensive examples.
Installation
Ruddy supports Python 3.11 to 3.14.
python -m pip install ruddy
For optional UMAP support:
python -m pip install "ruddy[manifold]"
For development setup with uv, see DEVELOPMENT.md.
Analyze a table
import polars as pl
from ruddy import TabularDataset, analyze_univariate, analyze_bivariate
frame = pl.DataFrame({
"id": ["s1", "s2", "s3", "s4", "s5", "s6"],
"activity": [1.2, 2.4, 1.8, 3.1, 2.9, 4.2],
"length": [10.0, 14.0, 12.0, 17.0, 15.0, 20.0],
"family": ["A", "A", "A", "B", "B", "B"],
})
dataset = TabularDataset(
frame,
id_column="id",
role_overrides={
"activity": "response",
"family": "factor",
"length": "covariate",
},
)
univariate = analyze_univariate(dataset)
bivariate = analyze_bivariate(dataset)
print(univariate.numeric_statistics)
print(bivariate.correlations)
To read files, use pl.read_csv(...) or pl.read_parquet(...). pandas
DataFrames work too. A column's role doesn't depend on its dtype, so a batch
stored as integers can still be declared a categorical factor. The
data contracts guide explains how observation IDs
are checked and aligned.
Analyze a feature space
from ruddy import FeatureMatrix, analyze_pca
features = FeatureMatrix(
dataset.frame.select("activity", "length"),
observation_ids=dataset.observation_ids,
)
pca = analyze_pca(features, n_components=2, scaling="standard")
print(pca.scores)
print(pca.variance)
FeatureMatrix also takes NumPy arrays and SciPy sparse matrices. Not every
method accepts sparse input, and Ruddy raises an error rather than densify it
behind your back. To compare two feature spaces, give both of them observation
IDs:
# Given two FeatureMatrix objects named space_a and space_b:
from ruddy import analyze_representation_similarity
comparison = analyze_representation_similarity(
space_a,
space_b,
alignment="strict",
cca_components=2,
random_state=42,
)
print(comparison.cka)
print(comparison.mantel)
The method reference lists every analysis with its assumptions and how to read its output. Besides the ones above, Ruddy has group comparisons, bootstrap intervals, factorial and mixed-effects models, PERMANOVA, compositional data, Bayesian summaries and anomaly flags.
Run several analyses
from ruddy import AnalysisConfig, analyze
result = analyze(
dataset,
config=AnalysisConfig(
enabled_blocks=("profiling", "univariate", "groups", "outliers"),
responses=("activity",),
groups=("family",),
random_state=42,
),
)
print(result.summary())
By default only profiling and univariate analysis run. The unified analysis guide covers the other blocks and their parameters.
Command line
ruddy --help
ruddy analyze bivariate data.csv \
--id-column id \
--factor family \
--output-dir results
The commands are grouped under inspect, analyze, model and project.
ruddy pipeline runs several blocks in one go, but only the ones you select.
The CLI reference documents every option and the
files each command writes.
Design principles
Ruddy tries hard not to make decisions for you:
- Scaling and dimensionality reduction happen only when you ask for them. Missing values aren't imputed, and a string that looks like a number stays a string.
- Each analysis reports which observations it used. Excluding a row never deletes it from your data.
- A diagnostic never swaps the test you asked for. If a normality check fails, you still get the test you requested, with the diagnostic next to it.
- A rank-deficient problem is reported as such, not quietly regularized.
- Outliers are flagged and left alone.
- Data and annotations are matched by observation ID, never by row position.
- Every result records its parameters, input sizes, random seed and the Ruddy version that produced it.
Because of this, read status and reason next to every estimate. ok means
the quantity was estimated. degenerate means the data can't support it, for
example a constant column in a correlation. skipped means a requirement
wasn't met. Missing values in result tables are Polars nulls, not NaN. See
results and provenance for how to read and
export results.
Documentation and examples
The documentation index links all the guides. There are also 13 example notebooks written in marimo. To open one:
uv sync --all-extras --group examples
uv run marimo edit examples/01_profiling_univariate.py
Citing and license
If you use Ruddy in published work, please cite it using
CITATION.cff, or the "Cite this repository" button on
GitHub. Ruddy is released under the MIT license.
Metadata
Release files for ruddy 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| ruddy-0.1.0.tar.gz | 139.8 kB | With provenance | Details for ruddy-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| ruddy-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for ruddy-0.1.0-py3-none-any.whl |
Total release size: 342.4 kB
Release files / ruddy-0.1.0.tar.gz
| Download URL | ruddy-0.1.0.tar.gz |
|---|---|
| Size | 139.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
eefdef9ca8fde45e723f0e45d38a6599a912a7beb939f2e6f39a8696dda3bf3f
|
|
BLAKE2b-256 checksum How to use checksums |
a44cc7d35816d51bea6b2d8230645e3001f8d5c898ba5e6ce9c93b7707a13ced
|
| 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 23, 2026.
Transparency logRelease files / ruddy-0.1.0-py3-none-any.whl
| Download URL | ruddy-0.1.0-py3-none-any.whl |
|---|---|
| Size | 202.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
52f5ae554f425706b1937d854ad6a95d4b14c4b4e5fae38ecd65ceb81790d81e
|
|
BLAKE2b-256 checksum How to use checksums |
1b15710d23925624e439aec3fd191133aed97e2a2c3e1e4ac8e42d51979c4b1f
|
| 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 23, 2026.
Transparency logSecurity for ruddy 0.1.0
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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for ruddy-0.1.0.tar.gz
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 23, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.