CASPER-t
Covering Approximation Space Permutation Elimination Rule (t-statistic form) a reliability-weighted topological feature selector, packaged as a drop-in scikit-learn transformer.
Keep a small, confident subset of features instead of all of them without paying for it in accuracy. On 9 benchmark datasets CASPER-t retains a median 60 % of features while tracking full-feature accuracy to within ~1–2 points.
pip install casper-fs
How it works
CASPER-t treats each feature's usefulness as a measured quantity with an error bar, and keeps a feature only when its measured contribution clears a reliability margin not merely when it looks large once.
flowchart LR
A["X, y"] --> B["Jenks<br/>discretization"]
B --> C["L₁ tolerance<br/>relation"]
C --> D["select ε*<br/>(covering radius)"]
D --> E["γ-PFI<br/>N permutations"]
E --> F["tᶠ = (Δγ − Q1) / SEM > κ"]
F --> G["selected<br/>subset"]
-
Discretize each feature by unsupervised Jenks natural breaks.
-
Build an L₁ tolerance relation and pick the covering radius ε* that maximises the γ dependency degree (just below saturation).
-
Score every feature by the drop in γ under N permutations (γ-PFI). A permutation-importance signal native to the covering approximation space.
-
Retain a feature only when that drop clears the first quartile of the feature-wise distribution by a reliable margin:
tᶠ = (mean(Δγ_f) − Q1) / SEM_f > κ (default κ = 1.5)
Everything is refit on the training split it is given, so it is leakage-free
inside a scikit-learn Pipeline / cross-validation loop.
Benchmark
Protocol. Nested cross-validation on 9 datasets, evaluated across 8 classifiers, against 13 feature-selection baselines (filter, wrapper, embedded, and rough-set families). Baselines are compared at matched cardinality. Each is truncated to CASPER-t's own per-fold feature count. So, every method is judged on the same feature budget.
The headline is parsimony. CASPER-t discards 25–51 % of the features yet stays within a point or two of using everything and matches or beats the full set on 4 of 9 datasets (banknote, diabet, htru2, sonar).
| Dataset | Features kept (K / p) | CASPER-t acc. | All-features acc. | Δ |
|---|---|---|---|---|
| banknote | 3.0 / 4 | 96.8 | 97.1 | −0.2 |
| htru2 | 5.7 / 8 | 97.1 | 97.0 | +0.1 |
| magic | 7.0 / 10 | 81.2 | 82.5 | −1.3 |
| diabet | 6.7 / 10 | 77.6 | 76.5 | +1.1 |
| phoneme | 3.0 / 5 | 77.7 | 81.9 | −4.2 |
| cyron | 3.6 / 6 | 84.9 | 87.7 | −2.9 |
| sonar | 34.0 / 60 | 80.3 | 80.2 | +0.2 |
| parkinson | 8.4 / 17 | 86.2 | 86.4 | −0.3 |
| kanser | 12.7 / 26 | 94.2 | 96.0 | −1.8 |
Accuracy is the mean over 8 classifiers × outer folds. K is the mean per-fold subset size, p is the number of candidate features.
On honest terms. At a matched feature budget no single selector dominates the
field. CASPER-t's mean Accuracy rank is mid-pack (≈ 7.7 of 14 methods), and
its value is the combination of a principled topological criterion with a
reliability gate that yields compact subsets. Every rank, dispersion (fold std and
across-classifier std), and per-fold number behind these figures is shipped in
detailed_tables/, nothing is averaged away.
Quickstart
from casper import CasperT
from sklearn.pipeline import Pipeline
from sklearn.svm import SVC
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_breast_cancer
X, y = load_breast_cancer(return_X_y=True)
# standalone
sel = CasperT(kappa=1.5, n_permutations=30, random_state=42).fit(X, y)
print(sel.get_support().sum(), "features selected") # -> 13 of 30
print(sel.eps_star_, sel.t_stats_) # diagnostics
# leakage-free inside a Pipeline (refits per fold)
pipe = Pipeline([("casper", CasperT()), ("clf", SVC())])
cross_val_score(pipe, X, y, cv=5)
Requires Python ≥ 3.9, numpy, scipy, scikit-learn. Install from a clone with
pip install ..
API
CasperT(kappa=1.5, n_permutations=30, max_bins=7, target_gvf=0.80, max_topological=3000, random_state=42)
| Parameter | Meaning |
|---|---|
kappa |
reliability margin of the tᶠ rule; larger ⇒ fewer, more confident features |
n_permutations |
permutation replicates per feature in γ-PFI |
max_bins / target_gvf |
Jenks bin cap / goodness-of-variance-fit early-stop target |
max_topological |
subsample cap for the O(n²) topological stage (evaluation uses full data) |
Fitted attributes: support_, delta_gamma_, sem_, t_stats_, eps_star_,
gamma_base_, q1_. Standard SelectorMixin API: fit, transform,
get_support, get_feature_names_out.
Reproducing the article
pipeline/gamma_pfi_uhem.py is the full nested-CV pipeline used for the paper
(all baselines, statistics, and per-fold outputs); pipeline/make_tables.py
regenerates the LaTeX tables from those outputs.
Detailed results (detailed_tables/)
The article's tables report means only, for readability. These files hold the same numbers with their dispersion and at fold-level granularity:
| File | What it is |
|---|---|
summary_mean_std.csv |
one row per (dataset × method × metric): mean, fold std, across-classifier std, retained K, p, retained % |
fold_level_hybrid.csv |
every outer fold, HYBRID classifier only |
fold_level_raw.csv.gz |
every outer fold × 8 classifiers × every method |
Method ids: V1_tstat = CASPER-t; *_matchK = baselines truncated at CASPER-t's
per-fold cardinality; *_native = rough-set baselines at their own stopping point;
ALL = full feature set.
Citation
If you use CASPER-t, please cite the article:
@article{casper_t,
title = {A Topological Feature Selection Framework via Generalized Covering
Approximation Spaces with Permutation Importance},
authors = {Uğur Yiğit, Kenan Evren Boyabatlı, Ebrar Karakurt, Esma Nur Elgün and
Ertan Sönmez},
journal = {Preprint - Appearing}
year = {2026}
}
License
MIT — see LICENSE.
Release files for casper-fs 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| casper_fs-0.1.2.tar.gz | 332.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| casper_fs-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 343.1 kB
Release files / casper_fs-0.1.2.tar.gz
| Download URL | casper_fs-0.1.2.tar.gz |
|---|---|
| Size | 332.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
dc6d88eb77edbbf8ba04f34988e55d886f37c70b7973672b4d22b850d1638bac
|
|
BLAKE2b-256 checksum How to use checksums |
7aa2e2dffc361681f920d8df0cfa509006e644b79ad3c26a6afdff36db793c43
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / casper_fs-0.1.2-py3-none-any.whl
| Download URL | casper_fs-0.1.2-py3-none-any.whl |
|---|---|
| Size | 10.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
50ae4facd9bbf4999e2294409c4c8035b7c8e8612c4db2c197b5428511cf1211
|
|
BLAKE2b-256 checksum How to use checksums |
7b18f432633a218c63232972a455156e088e77d579041d153e7cf5c6ec471bdb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|