Metadata-Version: 2.4
Name: moofs
Version: 0.1.0
Summary: Multi-objective feature selection with a scikit-learn API: MOFS-RFGA, NSGA-II, Pareto-front visualization and PlatEMO-compatible metrics
Author: Herman Motcheyo
License: MIT
Project-URL: Homepage, https://github.com/Herman-Motcheyo/moofs
Keywords: feature-selection,multi-objective,nsga2,spea2,moead,sparseea,pso,relieff,benchmark
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.21
Requires-Dist: pandas>=1.3
Requires-Dist: scikit-learn>=1.0
Requires-Dist: matplotlib>=3.5
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Provides-Extra: docs
Requires-Dist: mkdocs>=1.6; extra == "docs"
Requires-Dist: mkdocs-material>=9.5; extra == "docs"
Requires-Dist: mkdocstrings[python]>=0.25; extra == "docs"
Dynamic: license-file

# moofs

**Multi-Objective Optimization for Feature Selection**

A Python library for multi-objective feature selection with a unified, scikit-learn compatible API. `moofs` searches for the best trade-offs between **classification error** and **number of selected features**, returns the full Pareto front, and lets you pick the subset that fits your needs.

## Installation

```bash
pip install moofs
```

## Quick start

```python
from moofs import MOFSSelector

selector = MOFSSelector(algorithm="mofs-rfga", max_evals=5000, random_state=0)
X_reduced = selector.fit_transform(X, y)

selector.pareto_front_   # (n_solutions, 2): [error %, subset size]
selector.support_        # boolean mask of the chosen subset
selector.get_feature_names_out()
```

It drops into any scikit-learn pipeline:

```python
from sklearn.pipeline import Pipeline
from sklearn.neighbors import KNeighborsClassifier

pipe = Pipeline([
    ("fs", MOFSSelector(max_evals=5000, random_state=0)),
    ("clf", KNeighborsClassifier(n_neighbors=3)),
]).fit(X_train, y_train)
```

## Available algorithms

| Algorithm | Key | Authors | Reference |
|-----------|-----|---------|-----------|
| **MOFS-RFGA** | `mofs-rfga` | Xue, Zhu & Neri (2023) | [paper](https://doi.org/10.1016/j.asoc.2023.109987) |
| **NSGA-II** | `nsga2` | Deb, Pratap, Agarwal & Meyarivan (2002) | [paper](https://doi.org/10.1109/4235.996017) |

More algorithms from the MOFS literature (SparseEA, NSGA-II/SDR, SPEA2, MOEA/D, NSPSOFS, CMDPSOFS) are planned for upcoming releases — see the [CHANGELOG](CHANGELOG.md).

## Visualizing Pareto fronts

```python
from moofs import plot_selector, plot_fronts

plot_selector(selector)              # front + highlighted chosen subset
plot_fronts({"MOFS-RFGA": r1, "NSGA-II": r2}, reference=True)
```

## Metrics

Quality indicators follow the **PlatEMO definitions** used in the MOFS literature, so values are directly comparable with published tables: `igd`, `hv` (normalized, reference point (1,1)), `coverage` (weak dominance), `nfs`, `spacing`.

```python
from moofs import compare

table = compare({"MOFS-RFGA": r1, "NSGA-II": r2})
#   algorithm    IGD     HV   NFS  best_error_%  min_subset_size
```

## Research-style API

For experiments and full control over the search:

```python
from moofs import FeatureSelectionProblem, MOFSRFGA, NSGA2

problem = FeatureSelectionProblem(X, y)   # KNN k=3, 3-fold CV, cached
result = MOFSRFGA(problem, pop_size=100, max_evals=300_000, seed=0).run()
result.F        # objective matrix of the Pareto front
result.front    # solutions with binary masks (.x)
```

The evaluation protocol follows the reference paper: k-NN (k=3) classifier, 3-fold cross-validation, objectives = (classification error %, subset size). Evaluations are memoized; cache hits still count toward `max_evals` so budgets stay comparable.

## Faithfulness notes

Implementations are traceable to their source papers, and ambiguities are documented rather than silently resolved. Notably, the MOFS-RFGA paper's Fig. 1 and its Algorithm 3 disagree on the crossover semantics; `moofs` defaults to the Fig. 1 reading (consistent with the mutation operator) and exposes `interpretation="pseudocode"` for the literal alternative. See the documentation for details.

## License

MIT — see [LICENSE](LICENSE).

## Citing

If you use `moofs` in academic work, please cite the underlying algorithm papers (see the table above). A citable software DOI is planned.
