Observed since 20 Oct, 21:07 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Clean-room Rust + PyO3 implementation of the AFISP core algorithms
A clean-room Rust + PyO3 implementation of the AFISP workflow: stability analysis to find worst-performing data subsets, then interpretable subgroup phenotyping.
Full documentation: DOCUMENTATION.md
Two Python APIs ship in one package:
| Import | Use when |
|---|---|
from afisp import … | You want the original sklearn-style API (fit(X, losses), optional EBM, plotting) |
from afisp_rs import … | You want the Rust-backed API (fit_from_mu_hat, fit_with_estimator, explicit backends) |
pip install afisp-rs
Original AFISP compatibility (EBM cross-fit, pandas, plotting, statsmodels):
pip install "afisp-rs[original]"
Demo extras (includes PyTorch surrogate losses):
pip install "afisp-rs[demo]"
Requires Python ≥ 3.9 and numpy. Prebuilt wheels are provided for common Linux, macOS, and Windows platforms. If no wheel matches your platform, pip builds from source and you will need Rust + Python dev headers.
import numpy as np
from sklearn.ensemble import RandomForestRegressor
from afisp_rs import WorstSubsetFinder, SubgroupPhenotyper, brier_loss
y_true = np.array([0, 1, 0, 1, 0, 1], dtype=np.uint8)
y_score = np.array([0.2, 0.8, 0.3, 0.7, 0.1, 0.9])
losses = np.asarray(brier_loss(y_true, y_score))
X = np.random.randn(len(losses), 3)
finder = WorstSubsetFinder(subset_fractions=[0.5, 1.0], eps=1e-8, random_state=7)
finder.fit_with_estimator(X, losses, RandomForestRegressor(random_state=7), cv=3)
print("Worst-case risks:", finder.r_hats_)
print("Subset masks:", finder.subset_masks())
subset_labels = finder.subset_masks()[0].astype(np.uint8)
phen = SubgroupPhenotyper(backend="sirus", random_state=7, sirus_num_trees=64)
phen.fit(
X,
subset_labels,
losses,
y_true=y_true,
y_score=y_score,
performance_threshold=0.6,
)
print(phen.summary_table())
from afisp import WorstSubsetFinder, SubgroupPhenotyper
# Requires: pip install "afisp-rs[original]"
# Uses ExplainableBoostingRegressor by default for conditional-loss cross-fit.
finder = WorstSubsetFinder(subset_fractions=[0.2, 0.4, 1.0], cv=10, eps=1e-5)
finder.fit(X, losses, feature_names=["age", "sex", "score"])
print(finder.R_hats_)
print(finder.confidence_intervals())
idx, effect = finder.find_max_effect_size()
For Rust-backed phenotyping through the compatibility layer, pass y_true, y_score, and performance_threshold to SubgroupPhenotyper.fit().
mu_hat)backend="sirus" — Rust-native stable rule forest (default)backend="conjunction" — deterministic conjunction miner (DecisionList fallback in afisp layer)See DESIGN.md for fidelity notes vs the upstream Python reference.
[dependencies]
afisp_rs = { version = "0.1", default-features = false }
Pure Rust usage (no Python):
use afisp_rs::WorstSubsetFinderCore;
let mut finder = WorstSubsetFinderCore::new(vec![0.2, 1.0], 0.0, 0);
finder.fit_from_mu_hat(losses, mu_hat, Some(fold_ids)).unwrap();
Enable the Python extension when building with maturin: --features extension-module.
git clone https://github.com/na399/afisp-rs.git
cd afisp-rs
python -m pip install maturin pytest numpy scikit-learn
maturin develop --release --features extension-module
pytest -q
cargo test --no-default-features
Full example: examples/demo.py
Maintainers: see PUBLISHING.md. Releases are automated on v* tags to PyPI (afisp-rs) and crates.io (afisp_rs).
MIT License. See LICENSE.
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.1.1 | 2 Sept 2026 | 10 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 21:07 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:c4ab6ae8b991f14843613571d3f368d8175a34b431ebbc3202c29dfdba6cba3e