Metadata-Version: 2.4
Name: ftir-optuna-automl
Version: 0.2.0
Summary: Framework de AutoML (pre-processamento FTIR + classificador, otimizados juntos via Optuna) construido sobre o ftir_prep.
Author-email: Lucas Mendonça <lucas.mendonca@example.com>
Maintainer-email: Lucas Mendonça <lucas.mendonca@example.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/lucas-mendonca-andrade/ftir-optuna-automl
Project-URL: Repository, https://github.com/lucas-mendonca-andrade/ftir-optuna-automl
Project-URL: Bug Tracker, https://github.com/lucas-mendonca-andrade/ftir-optuna-automl/issues
Keywords: ftir,spectroscopy,automl,optuna,machine-learning,bioinformatics
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Classifier: Topic :: Scientific/Engineering :: Chemistry
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: numpy
Requires-Dist: pandas
Requires-Dist: scikit-learn>=1.6.1
Requires-Dist: optuna>=3.0.0
Requires-Dist: xgboost>=2.1.3
Requires-Dist: psutil
Requires-Dist: joblib
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pydantic-settings>=2.0; extra == "dev"
Requires-Dist: build>=1.0; extra == "dev"
Requires-Dist: twine>=6.0; extra == "dev"

# FTIR-OPTUNA

Framework de AutoML para espectros FTIR: um único estudo [Optuna](https://optuna.org/) otimiza,
a cada trial, tanto o pipeline de pré-processamento (via [`ftir_prep`](../FTIR-Prep)) quanto a
escolha do classificador e seus hiperparâmetros — simultaneamente, não em etapas separadas.

Para o histórico de decisões de design, bugs encontrados/corrigidos e a investigação de
integração com o `amlb_ainet`, ver [`CLAUDE.md`](CLAUDE.md).

## Requisitos

- Python 3.9
- O pacote [`ftir_prep`](../FTIR-Prep) (não está no PyPI — instalado a partir de um wheel local, ver abaixo)

## Instalação

`ftir-optuna-automl` está no PyPI, mas depende do
[`ftir-prep`](https://pypi.org/project/ftir-prep/) — que também está, só que precisa ser
instalado **sem** resolver as dependências dele (o `ftir-prep` publicado pede `PyWavelets>=1.9.0`,
que não tem wheel para Python 3.9):

```bash
# 1. Crie e ative um venv
python3.9 -m venv venv
source venv/bin/activate

# 2. Instale o ftir-prep (PyPI, sem resolver as dependencias dele) + as dependencias
#    reais, com versoes que funcionam em Python 3.9
pip install --no-deps ftir-prep==0.3.1
pip install rampy==0.5.3 PyWavelets==1.6.0 statsmodels openpyxl shap matplotlib

# 3. Instale o ftir-optuna-automl
pip install ftir-optuna-automl
```

Para desenvolver este repositório em vez de só usar a biblioteca, clone o repositório e instale
em modo editável (`pip install -e .`) no lugar do passo 3 acima, depois instale as dependências
de dev:

```bash
git clone https://github.com/lucas-mendonca-andrade/ftir-optuna-automl.git
cd ftir-optuna-automl
pip install -e .
pip install -r requirements.txt   # suite de testes, notebook, empacotamento
```

## Configuração

Os caminhos de dataset não ficam hardcoded no código — vêm de variáveis de ambiente, carregadas
de um arquivo `.env` na raiz do projeto (não versionado; cada máquina tem o seu).

```bash
cp .env.example .env
# edite .env com os caminhos reais da sua maquina
```

| Variável | Obrigatória? | Usada por | Descrição |
|---|---|---|---|
| `TEA_DATA_PATH` | sim | notebook, testes | `.dat` com espectros + rótulos do dataset TEA |
| `TEA_WAVENUMBERS_PATH` | sim | notebook, testes | `.dat` com os números de onda (cm⁻¹) |
| `AMLB_TEA_DATA_DIR` | não (tem default) | script de simulação | diretório com os CSVs de fold do benchmark real |
| `AMLB_TEA_WAVENUMBERS_PATH` | não (tem default) | script de simulação | números de onda do benchmark real |

Se `TEA_DATA_PATH`/`TEA_WAVENUMBERS_PATH` estiverem faltando, a importação de `config` falha
imediatamente com uma mensagem clara (não um `FileNotFoundError` genérico no meio de uma busca).

## Uso rápido

```python
from config import settings
from ftir_prep import FTIRDataLoader
from ftir_optuna_automl import AutoMLOptunaOptimizer

# 1. Carregar os dados
loader = FTIRDataLoader(
    data_path=str(settings.tea_data_path),
    wavenumbers_path=str(settings.tea_wavenumbers_path),
)
X, y, wavenumbers = loader.load_data()

# 2. Rodar a busca conjunta (pre-processamento + classificador)
optimizer = AutoMLOptunaOptimizer(X, y, wavenumbers)
optimizer.optimize(
    time_budget_s=600,       # orcamento de tempo (segundos)
    memory_limit_mb=4096,    # teto de memoria (RSS), em MB
)

# 3. Ver o resultado
summary = optimizer.get_optimization_summary()
print(summary["best_classifier"], summary["best_value"])

# 4. Treinar o melhor pipeline no dado completo e salvar (p/ SHAP pos-hoc, ex.)
optimizer.fit_best()
optimizer.save_fitted_pipeline("models/tea")
```

### Notebook interativo

`optuna_automl.ipynb` cobre o mesmo fluxo com todos os parâmetros expostos (célula por célula,
com explicação de cada um). Abra com o kernel **"Python (ftir-optuna)"**:

```bash
python -m ipykernel install --user --name=ftir-optuna --display-name="Python (ftir-optuna)"
```

## Parâmetros principais

`AutoMLOptunaOptimizer(X, y, wavenumbers, ...)`:

| Parâmetro | Padrão | Descrição |
|---|---|---|
| `cv_method` | `"StratifiedKFold"` | ou `"StratifiedGroupKFold"`/`"GroupKFold"` (exigem `groups`) |
| `cv_n_splits` | `3` | número de folds usados para pontuar cada trial |
| `groups` | `None` | obrigatório para os dois métodos de CV acima |
| `metric` | `"balanced_accuracy"` | qualquer métrica de `sklearn.metrics.get_scorer_names()`, ou um scorer customizado |

`optimizer.optimize(...)`:

| Parâmetro | Obrigatório | Descrição |
|---|---|---|
| `time_budget_s` | sim | orçamento de tempo total, em segundos |
| `memory_limit_mb` | sim | teto de memória (RSS) — total, dividido entre os workers se `n_jobs>1` |
| `storage_path` | não | persiste o estudo em SQLite; permite retomar uma busca interrompida |
| `n_jobs` | não (padrão `1`) | processos rodando trials em paralelo, compartilhando `storage_path` |
| `preset` | não (padrão `None`) | `None` (busca conjunta normal) ou `"structure_then_refine"` — ver abaixo |

### Preset `structure_then_refine`

Analogamente aos presets de frameworks como AutoGluon/MLJAR, `optimize(..., preset="structure_then_refine")`
divide `time_budget_s` em duas fases sequenciais, cada uma com metade do orçamento:

1. **Estrutura** (50%): busca só quais técnicas de pré-processamento e qual classificador usar, avaliando
   cada combinação com os hiperparâmetros *default* de cada técnica/modelo — sem tunar.
2. **Refino** (50%): fixa a estrutura vencedora da fase 1 e tuna só os hiperparâmetros dela, no mesmo espaço
   de busca condicional completo usado no modo sem preset.

```python
optimizer.optimize(
    time_budget_s=600,
    memory_limit_mb=4096,
    preset="structure_then_refine",
)
```

Depois de rodar, `optimizer.structure_study_`/`optimizer.refine_study_` dão acesso aos dois estudos Optuna
internos separadamente; `optimizer.best_pipeline_`/`optimizer.best_classifier_` (e `get_optimization_summary()`)
sempre refletem o resultado final da fase de refino.

## Rodando os testes

```bash
pytest
```

37 testes, cobrindo desde o comportamento default até cenários de concorrência real
(`n_jobs>1`), persistência/retomada, validação de orçamento de recursos e o preset
`structure_then_refine`.

## Estrutura do projeto

```
FTIR-OPTUNA/
├── src/ftir_optuna_automl/   # o pacote em si (instalavel via pip)
├── tests/                    # suite pytest
├── config.py                 # carrega .env (caminhos de dataset deste repositorio)
├── optuna_automl.ipynb       # notebook interativo
├── simulate_amlb_ftir_tea_10min_acc.py  # simula o benchmark real do amlb_ainet
├── dist/                     # wheel buildado
└── pyproject.toml
```

## Licença

MIT
