PySuricata
Exploratory data analysis for Python, built on streaming algorithms.
PySuricata generates self-contained HTML reports for pandas and polars DataFrames. It processes data in chunks using streaming algorithms, so memory usage stays bounded regardless of dataset size.
Try it in your browser with no install: drop a CSV, Parquet file or Excel workbook and get the real report back. The profiler is compiled to WebAssembly and runs in the page, so nothing is uploaded.
-
Live Demo
Profile your own file in a browser tab. No install, no upload.
-
Quick Start
Install PySuricata and generate your first report.
-
Why PySuricata?
Understand the streaming architecture and design decisions.
-
User Guide
Detailed guides for configuration, advanced features, and more.
-
API Reference
profile(),summarize(),compare()and every option they take.
Features
- Streaming processing — Data is processed in configurable chunks, keeping memory bounded in rows regardless of dataset size. Useful for datasets that don't fit in RAM.
- Reads a source, not just a frame — A path, an Arrow table or reader, anything exporting
__arrow_c_stream__, or a DuckDB relation, all a batch at a time and never materialised. 307 MB against 581 MB on a 180 MB Parquet file. - Numbers without the HTML —
summarize()returns the same statistics as a versioned JSON payload, so a consumer can read it without parsing a report. - A gate, not just a report —
pysuricata checkcompares a dataset against a stored baseline and exits non-zero when a threshold is crossed, so the same single pass runs in a notebook and in CI. - A diff between two datasets —
compare(a, b)reports every delta: schema, dataset and per column, with the approximate ones marked. - Mathematically grounded — Welford's algorithm for numerically stable moments, Pébay's formulas for mergeable statistics, KMV sketches for distinct counts, Misra-Gries for heavy hitters — each with its error bound published rather than hidden.
- Pandas and Polars support — Works natively with both
pandas.DataFrameandpolars.DataFrame/polars.LazyFrame. - Self-contained reports — A single HTML file with inline CSS, JS and SVG charts. No external assets or dependencies needed to view.
- Reproducible by default — The seed is
0, notNone, so re-running over unchanged data is a no-op rather than a set of sampling wobbles.
Installation
This installs PySuricata along with its dependencies: pandas, numpy (on Python ≥3.13), and markdown.
To also install polars support:
Quick Example
import pandas as pd
from pysuricata import profile
# Two years of hourly bike rentals — a timestamp, two booleans, two
# categoricals, and numeric columns that genuinely correlate.
url = "https://raw.githubusercontent.com/alvarodiez20/pysuricata/main/docs/assets/bike_sharing.csv"
df = pd.read_csv(url, parse_dates=["rented_at"])
# Generate report
report = profile(df)
report.save_html("example_report.html")
Or from a shell, without writing a script:
This is the actual report generated from the code above (17,379 rows × 12 columns):
Can't see the report? Open in new tab →
How It Works
PySuricata reads data in chunks and updates lightweight accumulators for each column. This means:
| Aspect | Approach |
|---|---|
| Memory | Bounded by chunk size + accumulator state, not dataset size |
| Speed | Single pass over the data — each row is read once |
| Accuracy | Exact for moments (mean, variance, skewness, kurtosis); approximate with known error bounds for distinct counts and top-k |
| Mergeability | Accumulators can be merged across chunks or machines |
Memory is bounded in rows. It is not bounded in columns: state is per column at roughly 529 KB each, and a 20,000 x 600 frame peaks at 631 MB against 344 MB for a 1,000,000 x 14 one on more cells. That is a known limit, tracked in #207.
Reports include per-column statistics, histograms, correlation chips, missing value analysis, outlier detection, and more — all computed during the single streaming pass.
Beyond the Report
-
Gate a build on drift
pysuricata checkcompares against a stored baseline and exits non-zero when a threshold is crossed. -
Read a source, not a frame
Parquet, Arrow IPC and DuckDB relations, a batch at a time.
-
Diff two datasets
compare(a, b)reports every delta, with the approximate ones marked. -
Read the numbers directly
A versioned JSON payload with no HTML in the way.
Next Steps
-
New to PySuricata?
Start with the Quick Start Guide
-
Want specific examples?
Check the Examples Gallery
-
Interested in the algorithms?
Explore Statistical Methods
-
Want to contribute?
Read the Contributing Guide
Community & Support
License
MIT License. See LICENSE for details.