Metadata-Version: 2.4
Name: tiny-slate
Version: 0.1.0
Summary: SLATE: a tiny, interpretable, scikit-learn-compatible additive threshold classifier.
Project-URL: Homepage, https://github.com/goginenisaikiran/tinyslate
Project-URL: Repository, https://github.com/goginenisaikiran/tinyslate
Project-URL: Issues, https://github.com/goginenisaikiran/tinyslate/issues
Author-email: Saikiran Gogineni <goginenisaikiran31677@gmail.com>
Maintainer-email: Saikiran Gogineni <goginenisaikiran31677@gmail.com>
License: MIT
License-File: LICENSE
Keywords: additive-model,classifier,glassbox,interpretable-ml,machine-learning,scikit-learn,sparse
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.9
Requires-Dist: numpy>=1.22
Requires-Dist: scikit-learn>=1.0
Provides-Extra: test
Requires-Dist: pytest>=7.0; extra == 'test'
Description-Content-Type: text/markdown

# tinyslate

**SLATE** — *Sparse Lightweight Additive Threshold Ensemble* — is a tiny,
fully interpretable, [scikit-learn](https://scikit-learn.org)-compatible
classifier.


## Install

```bash
pip install tiny-slate
```

Note the import name keeps no hyphen (Python identifiers cannot contain one):

```python
from tinyslate import SlateClassifier
```

## Quick start

```python
from tinyslate import SlateClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

clf = SlateClassifier(budget=32).fit(X_train, y_train)

print("accuracy:", clf.score(X_test, y_test))
print("probabilities:", clf.predict_proba(X_test[:3]))
print("atoms used:", clf.n_atoms_)
print("footprint (bytes):", clf.memory_bytes_)
```

Because it follows the scikit-learn estimator API, it drops straight into
pipelines and model selection:

```python
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import GridSearchCV

pipe = make_pipeline(StandardScaler(), SlateClassifier())
grid = GridSearchCV(
    pipe,
    {"slateclassifier__budget": [16, 32, 64],
     "slateclassifier__learning_rate": [0.3, 0.5]},
    cv=3,
)
grid.fit(X_train, y_train)
```

## Why SLATE

- **Interpretable by construction** — a prediction is a sum of signed rule
  contributions; there is no post-hoc approximation.
- **Tiny and fixed-size** — storage is `budget * (1 threshold + n_classes
  coefficients)` plus `n_classes` intercepts, independent of dataset size.
- **Shared atoms** — one rule pool serves every class, so a `K`-class model is
  far smaller than `K` independent one-vs-rest scorers.
- **Standard API** — `fit`, `predict`, `predict_proba`, `decision_function`,
  `score`, `explain`, `get_params`/`set_params`; works with `Pipeline`,
  `GridSearchCV`, `cross_val_score`, and `clone`.

## Parameters

| Parameter | Default | Meaning |
|---|---|---|
| `budget` | `64` | Max number of shared threshold atoms (capacity / sparsity). |
| `n_bins` | `32` | Quantile bins proposed per feature for candidate thresholds. |
| `max_iter` | `None` | Boosting iterations; `None` → `min(1200, 6*budget)`. |
| `learning_rate` | `0.5` | Shrinkage on each Newton update. |
| `l2` | `2.0` | Ridge regularization on the Hessian (> 0). |
| `l1` | `1e-3` | Lasso penalty in the corrective pass (prunes atoms). |
| `corrective_every` | `5` | Run a corrective refit every N iterations. |
| `corrective_passes` | `2` | Coordinate sweeps per corrective refit. |
| `tol` | `1e-9` | Minimum Newton gain to keep adding atoms. |
| `random_state` | `0` | Accepted for API compatibility; fitting is deterministic. |

## Fitted attributes

`classes_`, `n_features_in_`, `intercept_`, `atom_feature_`, `atom_threshold_`,
`atom_coef_`, `n_atoms_`, plus the introspection helpers `n_parameters_`,
`memory_bytes_`, and `footprint_bytes()`.

## Inspecting the rules

Because the model is additive, every prediction decomposes exactly into an
intercept plus the contribution of each rule that fired. Use `explain`:

```python
clf = SlateClassifier(budget=16).fit(X_train, y_train)

for e in clf.explain(X_test[:1]):
    print("predicted:", e["predicted_class"], "  score:", round(e["score"], 3))
    print("intercept:", round(e["intercept"], 3))
    for a in e["atoms"]:                       # sorted by |contribution|
        print(f"  feature[{a['feature']}] <= {a['threshold']:.3f}"
              f"  ->  {a['contribution']:+.3f}")
```

`intercept + sum(contributions)` equals the class score exactly, so the
explanation is faithful, not an approximation. Pass `class_index=k` to decompose
the score of a specific class instead of the predicted one. The raw rule pool is
also available directly via `atom_feature_`, `atom_threshold_`, and
`atom_coef_`.

## Requirements

- Python ≥ 3.9
- numpy ≥ 1.22
- scikit-learn ≥ 1.0

## License

MIT © Saikiran Gogineni
