Metadata-Version: 2.5
Name: ml-prism
Version: 0.1.0
Summary: ML Prism: automatic, explainable data readiness and machine-learning reports.
Project-URL: Homepage, https://github.com/Lima-Ricardo/ML_Prism
Project-URL: Documentation, https://github.com/Lima-Ricardo/ML_Prism#readme
Project-URL: Source, https://github.com/Lima-Ricardo/ML_Prism
Project-URL: Issues, https://github.com/Lima-Ricardo/ML_Prism/issues
Project-URL: Changelog, https://github.com/Lima-Ricardo/ML_Prism/blob/main/CHANGELOG.md
Author: Ricardo Lima
License-Expression: MIT
License-File: LICENSE
Keywords: automl,data-quality,explainable-ai,machine-learning,plotly
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
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.10
Requires-Dist: jinja2<4,>=3.1
Requires-Dist: numpy<3,>=1.26
Requires-Dist: pandas<3,>=2.1
Requires-Dist: plotly<7,>=5.24
Requires-Dist: scikit-learn<2,>=1.4
Provides-Extra: dev
Requires-Dist: bandit[toml]<2,>=1.8; extra == 'dev'
Requires-Dist: build<2,>=1.2; extra == 'dev'
Requires-Dist: hypothesis<7,>=6.100; extra == 'dev'
Requires-Dist: pip-audit<3,>=2.7; extra == 'dev'
Requires-Dist: pytest-cov<7,>=5; extra == 'dev'
Requires-Dist: pytest-timeout<3,>=2.3; extra == 'dev'
Requires-Dist: pytest<10,>=9.0.3; extra == 'dev'
Requires-Dist: ruff<1,>=0.9; extra == 'dev'
Requires-Dist: twine<8,>=6; extra == 'dev'
Description-Content-Type: text/markdown

# ML Prism

**Português** · [English](#english)

ML Prism é uma biblioteca Python em desenvolvimento para verificar dados, explicar sua prontidão,
sugerir possíveis variáveis-alvo, executar transformações auditáveis e produzir gráficos Plotly e
relatórios HTML. A interface foi desenhada para iniciantes, sem impedir o acesso aos objetos técnicos.

> **Estado atual:** `0.1.0` (primeira versão pública). A API implementada cobre `check()`, `auto_etl()`,
> sugestões de target, readiness, Model Arena para classificação/regressão/forecasting, tuning,
> Trusted Leaderboard, métricas, intervalos empíricos, explainability por permutação, predictions,
> drift por PSI, gráficos e relatório.
> Não use esta versão para decisões críticas sem validação independente.

## Nomes sem ambiguidade

| Contexto | Nome correto |
|---|---|
| Produto e interface | **ML Prism** |
| Instalação no PyPI | `pip install ml-prism` |
| Importação em Python | `from ml_prism import ...` |
| Repositório | `ML_Prism` |

O nome instalado usa hífen, como é comum no PyPI; o módulo Python usa sublinhado. O pacote não instala
nem sobrescreve um módulo chamado `prism`, evitando colisão com projetos preexistentes.

## O que o ML Prism faz agora

- aceita um `pandas.DataFrame` ou caminho para CSV, JSON, Parquet e Excel;
- valida entradas sem alterar silenciosamente o DataFrame original;
- detecta nulos, duplicatas e colunas constantes;
- calcula um score de prontidão com componentes explicáveis;
- sugere targets para classificação, regressão ou análise temporal;
- executa Auto-ETL configurável e registra cada transformação;
- expõe figuras Plotly como objeto, dicionário, JSON ou fragmento HTML;
- gera relatório offline em português ou inglês, com tema claro e Dracula;
- organiza visualizações em seções responsivas com zoom, pan e rolagem horizontal.
- compara três famílias de modelos sem usar o holdout para escolher o vencedor;
- ajusta automaticamente o campeão e calcula métricas em dados separados;
- produz um Model Trust explicável e penalizado por riscos documentados;
- cria previsões com probabilidades quando o estimador oferece `predict_proba()`.
- treina forecasting com separação e validação cronológicas, sem embaralhar passado e futuro.
- oferece intervalos empíricos para regressão e forecasting, calibrados fora da amostra.
- calibra probabilidades de classificação por padrão e mede confiabilidade no holdout.
- compara dados atuais com um baseline resumido para detectar drift de features.

## Instalação

Instale a versão pública com:

```bash
python -m pip install ml-prism
```

Para contribuir ou executar a suíte completa dentro do repositório:

```bash
python -m venv .venv
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
```

Ative o ambiente virtual usando o comando apropriado ao seu sistema. O ML Prism requer Python 3.10 ou
superior. As versões exatas suportadas são verificadas pela automação do repositório.

## Primeiro diagnóstico

```python
import pandas as pd
from ml_prism import check

data = pd.DataFrame(
    {
        "idade": [24, 39, None, 51],
        "plano": ["basic", "pro", "basic", "pro"],
        "churn": [0, 1, 0, 1],
    }
)

analysis = check(data)

print(analysis.readiness.overall)
print(analysis.target_suggestions)
```

`check()` não limpa os dados nem treina modelos. Ele cria uma cópia defensiva, analisa o conteúdo e
retorna um objeto `Analysis`.

### `check(data, *, target_limit=10)`

| Parâmetro | Obrigatório | Padrão | Descrição |
|---|---:|---:|---|
| `data` | Sim | — | `DataFrame` ou caminho para um arquivo suportado. |
| `target_limit` | Não | `10` | Máximo de sugestões retornadas. Aceita de 1 a 100. |

Retorna `Analysis`, contendo:

| Atributo/método | O que entrega |
|---|---|
| `data` | Cópia do DataFrame analisado. |
| `profile` | Dimensões, tipos gerais, nulos, duplicatas, constantes e problemas. |
| `readiness` | Score geral e seus quatro componentes. |
| `target_suggestions` | Sugestões ordenadas, com motivos e alertas. |
| `charts` | Nomes dos gráficos disponíveis. |
| `chart(name)` | Um `PrismChart` independente. |
| `to_dict()` | Resultado serializável para APIs ou sistemas próprios. |
| `report(...)` | Cria o relatório HTML opcional. |

## Entendendo o Readiness

O score não representa “certeza de que um modelo funcionará”. Ele resume verificações observáveis:

- **Completeness (35%)**: proporção de células preenchidas;
- **Consistency (25%)**: penalização por linhas exatamente duplicadas;
- **Validity (20%)**: penalização por colunas sem variação;
- **Modelability (20%)**: combinação inicial de consistência e validade.

Essa fórmula é propositalmente simples e auditável nesta fase. Ela deverá evoluir com testes e dados
reais. Use `analysis.readiness.explanation` para mostrar a explicação ao usuário.

## Sugestões de target

```python
for suggestion in analysis.target_suggestions:
    print(suggestion.column)
    print(suggestion.problem_type)
    print(suggestion.suitability)
    print(suggestion.reasons)
    print(suggestion.warnings)
    print(suggestion.time_column)
```

O percentual é uma adequação heurística para investigação, não confiança estatística. O ML Prism reduz o
score quando encontra muitos nulos, cardinalidade semelhante a identificador ou nomes como `id`,
`uuid` e `key`. A escolha final continua sendo do usuário.

Uma mesma coluna numérica pode aparecer mais de uma vez: regressão responde “quais features explicam
este valor?”, enquanto forecasting responde “como este valor evolui no tempo?”. Forecasting só é
sugerido quando existe exatamente uma candidata temporal segura. A data aparece em `time_column` e
nunca é apresentada como o próprio target.

Para inspecionar e executar uma sugestão pelo ranking de 1 em diante:

```python
suggestion = analysis.suggestion(1)
print(suggestion.column, suggestion.problem_type, suggestion.time_column)

result = analysis.learn_suggested(
    1,
    config=LearnConfig(
        cv_folds=3,
        tuning=True,
    ),
)
```

`learn_suggested()` transfere o nome do target, o tipo do problema e a coluna temporal. Configurações
opcionais continuam disponíveis, mas um `task` conflitante gera erro explícito. A sugestão é uma
hipótese para validação; ela não substitui a escolha do problema de negócio.

## Auto-ETL

```python
from ml_prism import auto_etl

result = auto_etl(data)

clean_data = result.data
print(result.actions)
print(result.decisions)
print(result.readiness_before.overall)
print(result.readiness_after.overall)
```

Defaults:

- remove duplicatas exatas;
- preenche nulos numéricos com a mediana;
- preenche nulos textuais com `"missing"`;
- preserva colunas constantes.

O DataFrame recebido não é modificado.

### Personalização

```python
from ml_prism import ETLConfig, auto_etl

config = ETLConfig(
    drop_duplicates=False,
    missing_numeric="keep",
    missing_text="keep",
    non_finite_numeric="keep",
    drop_constant_columns=False,
)

result = auto_etl(data, config=config)
```

| Opção | Padrão | Valores aceitos |
|---|---|---|
| `drop_duplicates` | `True` | `True`, `False` |
| `missing_numeric` | `"median"` | `"median"`, `"mean"`, `"zero"`, `"keep"` |
| `missing_text` | `"missing"` | `"missing"`, `"empty"`, `"keep"` |
| `non_finite_numeric` | `"as_missing"` | Converte `±inf` em nulo ou usa `"keep"`. |
| `drop_constant_columns` | `False` | `True`, `False` |
| `missing_numeric_columns` | `None` | Todas as numéricas ou uma lista explícita. |
| `missing_text_columns` | `None` | Todas as não numéricas ou uma lista explícita. |
| `non_finite_numeric_columns` | `None` | Todas as numéricas ou uma lista explícita. |
| `constant_columns` | `None` | Todas as constantes ou uma lista explícita. |

Se o usuário declarar uma opção, ela vence o comportamento automático. Antes de imputar, confirme se
a ausência de um valor não representa uma informação de negócio.

### Escolher regras e colunas

`treat` restringe a execução somente às regras listadas:

```python
result = auto_etl(
    data,
    treat=["missing_numeric", "missing_text"],
)
```

`exclude` preserva regras específicas e sempre vence em caso de sobreposição:

```python
result = auto_etl(
    data,
    exclude=["duplicates", "non_finite_numeric"],
)
```

Regras aceitas:

- `duplicates`;
- `missing_numeric`;
- `missing_text`;
- `non_finite_numeric`;
- `constant_columns`.

Também é possível limitar cada transformação a colunas específicas:

```python
config = ETLConfig(
    missing_numeric="median",
    missing_numeric_columns=["sales", "quantity"],
    missing_text_columns=[],  # preserva todos os textos ausentes
    non_finite_numeric_columns=["sales"],
    drop_constant_columns=True,
    constant_columns=["debug_flag"],
)

result = auto_etl(
    data,
    config=config,
    exclude=["duplicates"],
)
```

Precedência:

1. `exclude` remove uma regra do fluxo;
2. `treat`, quando informado, define o conjunto permitido;
3. estratégias como `missing_numeric="keep"` ou `drop_duplicates=False` preservam dados;
4. seletores de colunas limitam onde a estratégia pode agir.

`actions` contém apenas transformações efetivamente realizadas. `decisions` registra `treat`,
`exclude` e seletores explícitos, inclusive listas vazias. Nomes inexistentes, tipos incompatíveis,
regras desconhecidas e seletores duplicados geram erro em vez de serem ignorados silenciosamente.

### Resultado, gráficos e relatório do Auto-ETL

```python
payload = result.to_dict()  # não inclui as linhas tratadas

result.chart("etl_readiness_comparison")
result.chart("etl_quality_comparison")

result.report(
    "ml-prism-etl-report.html",
    language="pt-BR",
    theme="light",
)
```

Os dois gráficos são objetos `PrismChart` e podem ser consumidos por Plotly/Plotly.js sem gerar o
relatório. No HTML opcional, eles entram na seção `auto-etl`, junto das métricas antes/depois,
`actions` e `decisions`. O restante do diagnóstico é recalculado sobre os dados tratados.

## Gráficos sem o relatório padrão

```python
chart = analysis.chart("readiness")

plotly_figure = chart.figure
python_dict = chart.to_dict()
json_for_frontend = chart.to_json()
html_fragment = chart.to_html(full_html=False)
```

Gráficos disponíveis atualmente:

- `readiness`: componentes do score de prontidão;
- `missingness`: colunas nas quais foram detectados valores ausentes.

Uso no Plotly.js:

```javascript
const figure = JSON.parse(jsonFromPrism);
Plotly.newPlot("chart", figure.data, figure.layout, {responsive: true});
```

O frontend da empresa controla HTML, CSS, identidade, componentes e navegação.

## Aprendizado automático, Model Arena e tuning

Depois de inspecionar os dados, escolha um target sugerido ou uma variável conhecida:

```python
result = analysis.learn("churn")
```

Também é possível começar diretamente:

```python
from ml_prism import learn

result = learn(data, target="churn")
```

O fluxo padrão:

1. copia e valida os dados;
2. remove linhas cujo target está ausente;
3. remove duplicatas exatas para reduzir vazamento entre treino e teste;
4. exclui features que sejam cópias exatas do target;
5. infere classificação ou regressão;
6. reserva 20% dos dados como holdout;
7. prepara números e categorias dentro de cada pipeline;
8. compara três candidatos usando validação cruzada apenas no treino;
9. escolhe o campeão pela média da métrica, estabilidade e tempo como desempates;
10. ajusta hiperparâmetros do campeão;
11. calibra probabilidades dentro do treino quando o problema é classificação;
12. avalia uma única vez no holdout;
13. calcula métricas, confiança, importância por permutação e gráficos;
14. reajusta o pipeline escolhido em todos os dados conhecidos para uso em `predict()`/`forecast()`.

### `LearnConfig`

```python
from ml_prism import LearnConfig

config = LearnConfig(
    task="auto",
    time_column=None,
    test_size=0.20,
    cv_folds=5,
    tuning=True,
    random_state=42,
    n_jobs=1,
    max_categories=50,
    permutation_repeats=5,
    drop_duplicates=True,
    probability_calibration="sigmoid",
)

result = analysis.learn("churn", config=config)
```

| Opção | Padrão | O que faz |
|---|---:|---|
| `task` | `"auto"` | Infere classificação/regressão; aceita também `classification`, `regression` e `forecasting`. |
| `time_column` | `None` | Coluna temporal. Com `task="auto"`, fornecê-la ativa forecasting. |
| `test_size` | `0.20` | Reserva 20% para avaliação final. Aceita 0,10–0,40. |
| `cv_folds` | `5` | Número máximo de divisões da validação cruzada. Aceita 2–10. |
| `tuning` | `True` | Busca hiperparâmetros para o campeão usando somente treino. |
| `random_state` | `42` | Mantém splits e modelos reproduzíveis. |
| `n_jobs` | `1` | Evita saturar a máquina por padrão; `-1` usa todos os núcleos. |
| `max_categories` | `50` | Limita categorias por feature no One-Hot Encoder. |
| `permutation_repeats` | `5` | Repetições da importância por permutação. |
| `drop_duplicates` | `True` | Remove duplicatas antes da separação; `False` preserva explicitamente. |
| `probability_calibration` | `"sigmoid"` | Classificação: `sigmoid`, `isotonic` ou `off`. |

### O que existe em `ModelResult`

- `champion_name`: modelo selecionado;
- `model`: pipeline Scikit-learn já treinado;
- `leaderboard`: candidatos, média e desvio da validação, tempo, trust e status;
- `metrics`: métricas finais do holdout;
- `trust`: componentes, evidências e limitações do Model Trust;
- `feature_importance`: DataFrame com importância e desvio;
- `best_params`: hiperparâmetros escolhidos;
- `warnings`: decisões e riscos detectados;
- `time_column`, `frequency`, `last_timestamp` e `test_time` quando o resultado é temporal;
- `probability_calibration`: método efetivamente usado na classificação;
- `chart(name)`, `predict(data)`, `forecast(...)`, `to_dict()` e `report(...)`.

Model Trust combina performance no holdout (45%), estabilidade da validação (25%), generalização
(20%) e readiness (10%). Alertas documentados aplicam uma penalização separada. Ele não representa
probabilidade de sucesso futuro nem substitui validação de negócio.

## Predictions

```python
new_customers = pd.DataFrame(...)
predictions = result.predict(new_customers)

print(predictions.data)
records_for_api = predictions.to_dict()
```

Todas as features usadas no treinamento precisam existir. Colunas adicionais são preservadas. Em
classificação, são adicionadas a previsão e uma coluna de probabilidade por classe. Categorias novas
são tratadas pelo encoder sem quebrar a execução.

Em regressão, `interval` adiciona limites inferior e superior:

```python
prediction = result.predict(new_data, interval=0.90)

print(prediction.data["revenue_prediction"])
print(prediction.data["revenue_prediction_lower"])
print(prediction.data["revenue_prediction_upper"])
print(prediction.interval_level)
```

O valor é opcional, aceita 0,50–0,999 e representa o nível solicitado. O default de `predict()` é
`None`, portanto as colunas extras só aparecem quando o usuário pede. Classificação não aceita esse
argumento; suas probabilidades usam o processo específico descrito abaixo.

### Probabilidades de classificação

Por padrão, o ML Prism aplica calibração sigmoide somente dentro dos dados de treino. O holdout continua
intocado até a avaliação final. Isso torna a coluna de probabilidade mais interpretável do que a saída
bruta do estimador, embora nunca a transforme em garantia.

```python
config = LearnConfig(probability_calibration="sigmoid")  # default conservador
result = learn(data, "churn", config=config)

print(result.metrics["log_loss"])
print(result.metrics["brier_score"])
result.chart("probability_calibration")
```

Opções:

- `sigmoid`: default; costuma ser mais estável com datasets pequenos e médios;
- `isotonic`: mais flexível, mas pode sobreajustar com poucos exemplos;
- `off`: preserva a probabilidade bruta do estimador e registra essa limitação no Model Trust.

A curva de confiabilidade está disponível para classificação binária. Quanto mais próxima da diagonal,
melhor a correspondência entre probabilidade prevista e frequência observada no holdout. O
`brier_score` varia de 0 a 1 e valores menores são melhores.

## Forecasting sem vazamento temporal

Forecasting prevê um valor numérico ao longo de uma coluna separada de data/hora. A data não deve ser
o target: neste exemplo, `demanda` é o target e `data` define a ordem temporal.

```python
from ml_prism import LearnConfig, learn

result = learn(
    vendas,
    target="demanda",
    config=LearnConfig(
        task="forecasting",
        time_column="data",
    ),
)

print(result.metrics)  # mae, rmse e r2 no período mais recente
print(result.frequency)  # por exemplo, "D" quando a frequência pôde ser inferida
result.chart("forecast")
```

O ML Prism ordena as linhas pelo tempo, usa o bloco mais recente como holdout e usa
`TimeSeriesSplit` dentro do treino. Não há split aleatório no fluxo temporal. A inferência automática
da coluna de tempo só ocorre quando existe exatamente uma candidata segura; informe `time_column`
quando houver dúvida.

Para uma série que utiliza apenas a data, o ML Prism consegue criar as datas futuras:

```python
next_week = result.forecast(7, interval=0.90)
print(next_week.data)
```

Se a frequência for irregular e não puder ser inferida, declare-a na previsão:

```python
next_months = result.forecast(3, frequency="MS")
```

Se o modelo usa fatores externos, como preço, campanha ou temperatura, seus valores futuros precisam
ser informados. O ML Prism deliberadamente não repete nem inventa esses dados:

```python
future = pd.DataFrame(
    {
        "data": pd.date_range("2027-01-01", periods=7, freq="D"),
        "campanha": [0, 0, 1, 1, 1, 0, 0],
    }
)
next_week = result.forecast(7, future_data=future)
```

Limites de segurança atuais:

- o target precisa ser numérico e finito;
- após separar o holdout, o bloco de treino precisa conservar pelo menos 10 linhas;
- esta primeira implementação aceita uma única série e um registro por timestamp;
- timestamps ausentes, inválidos ou duplicados são rejeitados;
- séries por loja, cliente ou produto devem ser separadas ou agregadas antes do treino;
- as estimativas e seus intervalos não garantem comportamento ou cobertura futuros.
- o intervalo usa uma largura global baseada em erros absolutos fora da amostra; ele pode não se
  adaptar a mudanças de volatilidade, sazonalidade ou distribuição.

O ML Prism registra duas métricas adicionais no holdout de regressão/forecasting:

- `interval_90_coverage`: fração observada dentro do intervalo empírico de 90%;
- `interval_90_mean_width`: largura média desse intervalo, na unidade do target.

Essas métricas são evidências históricas, não promessa de 90% de cobertura futura.

## Gráficos de modelos

```python
result.chart("leaderboard")
result.chart("feature_importance")
result.chart("prediction_distribution")
result.chart("confusion_matrix")  # classificação
result.chart("probability_calibration")  # classificação binária
result.chart("actual_vs_predicted")  # regressão
result.chart("forecast")  # forecasting; possui range slider e rolagem horizontal
```

Todos possuem `figure`, `to_dict()`, `to_json()` e `to_html()`.

## Monitoramento de drift

Depois do treinamento, compare um lote atual com a distribuição conhecida:

```python
drift = result.check_drift(current_data)

print(drift.status)  # stable, warning ou drifted
print(drift.overall)  # PSI médio
print(drift.drifted_features)  # features acima do threshold
print(drift.to_dict())

drift.chart().to_json()  # Plotly/Plotly.js independente do relatório
```

### `check_drift(data, *, threshold=0.20)`

| Parâmetro | Obrigatório | Padrão | Comportamento |
|---|---:|---:|---|
| `data` | Sim | — | DataFrame ou arquivo com todas as features monitoradas. |
| `threshold` | Não | `0.20` | Limite de PSI para `drifted`; aceita 0,05–1,0. |

Cada feature recebe:

- `stable`: PSI abaixo da metade do limite;
- `warning`: PSI entre metade do limite e o limite;
- `drifted`: PSI igual ou superior ao limite.

O baseline guarda somente bordas de quantis, proporções, taxas de ausência e hashes SHA-256 das
categorias mais frequentes. Ele não guarda as linhas do treino nem os valores categóricos originais.
Categorias novas entram em um bucket `other`; nulos possuem bucket próprio. A coluna temporal do
forecasting é excluída para que o avanço natural do relógio não gere um falso alerta.

O PSI é um sinal operacional, não um teste causal. Ele depende do tamanho e da janela do lote, não
mede mudança no relacionamento entre feature e target e não prova queda de performance. Investigue o
contexto de negócio antes de retreinar automaticamente.

## Relatório HTML

```python
analysis.report("relatorio-ml-prism.html")
```

Todos os parâmetros:

```python
analysis.report(
    "relatorio-ml-prism.html",
    language="pt-BR",
    theme="light",
    open_browser=False,
)
```

| Parâmetro | Obrigatório | Padrão | Valores/comportamento |
|---|---:|---:|---|
| `path` | Não | `ml-prism-report.html` | Destino `.html` ou `.htm`. |
| `language` | Não | `pt-BR` | `pt-BR` ou `en`. |
| `theme` | Não | `light` | `light` ou `dracula`. |
| `open_browser` | Não | `False` | Abre o arquivo apenas quando explicitamente solicitado. |

O relatório inclui Plotly localmente para continuar funcionando offline. Nomes de colunas e outros
textos vindos do dataset são escapados antes da inserção no documento. Cada gráfico declara sua seção,
possui ID próprio do Plotly, reage ao redimensionamento e fica dentro de uma área com rolagem horizontal.

## Erros comuns

- **“The dataset has no rows”**: o arquivo possui colunas, mas não observações.
- **“Column names must be unique”**: duas ou mais colunas têm o mesmo nome.
- **“Unsupported file type”**: converta para CSV, JSON, Parquet ou Excel.
- **“Unknown chart”**: consulte `analysis.charts` antes de chamar `chart()`.
- **Parquet/Excel não abre**: instale o engine opcional solicitado pelo Pandas, como `pyarrow` ou
  `openpyxl`. Esses pacotes ainda não são dependências obrigatórias do núcleo.

## Atualizações, segurança e qualidade

Dependabot propõe atualizações semanais. Elas não são incorporadas cegamente: precisam passar pela
matriz de Python, testes, lint, auditoria de código e auditoria de vulnerabilidades. Isso equilibra
atualização e estabilidade.

A CI exige no mínimo 98% de cobertura combinada de linhas e branches. A suíte atual alcança 100% nos
dois critérios; esse número complementa, mas não substitui, testes de stress, segurança e validade
estatística.

```bash
python -m ruff check .
python -m pytest -m "not stress" --cov=ml_prism
python -m pytest -m stress
python -m bandit -c pyproject.toml -r src
python -m pip_audit
```

Consulte [Estratégia de testes](docs/pt-BR/TESTES.md),
[Arquitetura](docs/pt-BR/ARQUITETURA.md), [Referência completa da API](docs/pt-BR/API.md) e
[Segurança](SECURITY.md). As evidências da primeira versão estão em
[Validação da release 0.1.0](docs/pt-BR/VALIDACAO_RELEASE_0.1.0.md).

## Roadmap após a versão 0.1.0

- calibração multiclasse avançada e análise por segmento;
- intervalos adaptativos e condicionais;
- forecasting agrupado e modelos sazonais especializados;
- janelas de monitoramento, label drift e alertas persistentes;
- persistência segura e versionada do modelo;
- prevenção e detecção de leakage mais profunda;
- benchmarks documentados em diferentes tamanhos de dados;
- automação da regressão visual e da auditoria de acessibilidade em múltiplos navegadores.

Consulte o [histórico de mudanças](CHANGELOG.md). Releases e tags posteriores continuam exigindo uma
decisão explícita do mantenedor.

---

## English

ML Prism is an in-development Python library for checking datasets, explaining readiness, suggesting
possible targets, applying auditable transformations, and producing independent Plotly charts and
optional HTML reports. It is designed for beginners while preserving access to technical objects.

> **Current status:** `0.1.0` (first public release). The implementation includes `check()`, `auto_etl()`,
> target suggestions, readiness, classification/regression/forecasting Model Arena, tuning, a trusted
> leaderboard, metrics, empirical prediction intervals, permutation explainability, predictions,
> feature drift monitoring, charts and reports.

## Unambiguous names

| Context | Correct name |
|---|---|
| Product and interface | **ML Prism** |
| PyPI installation | `pip install ml-prism` |
| Python import | `from ml_prism import ...` |
| Repository | `ML_Prism` |

The distribution uses a hyphen, as is customary on PyPI, while the import package uses an underscore.
ML Prism does not install or overwrite a top-level module named `prism`.

## Installation

```bash
python -m pip install ml-prism
```

ML Prism requires Python 3.10 or newer. The supported Python matrix is verified in CI.

## Quick start

```python
import pandas as pd
from ml_prism import check

data = pd.DataFrame(
    {
        "age": [24, 39, None, 51],
        "plan": ["basic", "pro", "basic", "pro"],
        "churn": [0, 1, 0, 1],
    }
)

analysis = check(data)
print(analysis.readiness.overall)
print(analysis.target_suggestions)
analysis.report("ml-prism-report.html", language="en")
```

### `check(data, *, target_limit=10)`

- `data` is required: pass a DataFrame or a supported dataset path.
- `target_limit` is optional and defaults to `10`; accepted range is 1–100.
- it returns `Analysis` and never intentionally mutates the supplied DataFrame.

`Analysis` exposes `data`, `profile`, `readiness`, `target_suggestions`, `charts`, `chart(name)`,
`suggestion(rank)`, `learn_suggested(rank, config=...)`, `to_dict()` and `report(...)`.

A numeric outcome may have both regression and forecasting suggestions because they answer different
questions. Forecasting is suggested only when exactly one safe time column exists; that column is
stored as `TargetSuggestion.time_column`, never presented as the target itself. `learn_suggested()`
transfers this metadata and rejects conflicting task configuration.

## Auto-ETL defaults and options

```python
from ml_prism import ETLConfig, auto_etl

result = auto_etl(
    data,
    config=ETLConfig(
        drop_duplicates=True,
        missing_numeric="median",
        missing_text="missing",
        non_finite_numeric="as_missing",
        drop_constant_columns=False,
        missing_numeric_columns=None,
        missing_text_columns=None,
        non_finite_numeric_columns=None,
        constant_columns=None,
    ),
    treat=None,
    exclude=None,
)
```

- `drop_duplicates`: optional, default `True`;
- `missing_numeric`: optional, default `median`; accepts `median`, `mean`, `zero`, `keep`;
- `missing_text`: optional, default `missing`; accepts `missing`, `empty`, `keep`;
- `non_finite_numeric`: optional, default `as_missing`; also accepts `keep`;
- `drop_constant_columns`: optional, default `False`.
- every `*_columns` selector is optional and defaults to `None` (all eligible columns).

Explicit user choices always override automation. `ETLResult` provides `data`, `before`, `after`,
`readiness_before`, `readiness_after`, transformation `actions` and scope `decisions`.

`treat` limits execution to `duplicates`, `missing_numeric`, `missing_text`,
`non_finite_numeric` and/or `constant_columns`. `exclude` removes rules and has final precedence.
Column selectors restrict each strategy; an empty selector intentionally preserves every eligible
column. Unknown rules, columns, incompatible types and duplicates raise explicit errors.

`ETLResult.to_dict()` serializes summaries without data rows. `chart("etl_readiness_comparison")` and
`chart("etl_quality_comparison")` return independent Plotly contracts. `report()` places both in the
optional `auto-etl` HTML section together with actions and scope decisions.

## Independent Plotly charts

```python
chart = analysis.chart("readiness")
chart.figure
chart.to_dict()
chart.to_json()
chart.to_html(full_html=False)
```

The resulting JSON can be passed directly to Plotly.js. Consumers do not need to use ML Prism's report.

## Automatic learning

```python
from ml_prism import LearnConfig, learn

result = learn(
    data,
    "churn",
    config=LearnConfig(
        task="auto",  # auto, classification, regression or forecasting
        time_column=None,  # set a column name for forecasting
        test_size=0.20,  # accepted: 0.10–0.40
        cv_folds=5,  # accepted: 2–10
        tuning=True,
        random_state=42,
        n_jobs=1,
        max_categories=50,
        permutation_repeats=5,
        drop_duplicates=True,
        probability_calibration="sigmoid",  # sigmoid, isotonic or off
    ),
)
```

ML Prism reserves holdout data before the arena, ranks candidates only with cross-validation evidence,
tunes only the champion on training data and evaluates once on holdout data. `ModelResult` exposes the
trained pipeline, leaderboard, metrics, trust evidence, feature importance, warnings, charts,
`predict()`, `forecast()`, `to_dict()` and `report()`.

```python
prediction = result.predict(new_data)
prediction.data
prediction.to_dict()

result.chart("feature_importance").to_json()
result.report("model-report.html", language="en", theme="dracula")
```

Regression and forecasting can request empirical intervals:

```python
prediction = result.predict(new_data, interval=0.90)
forecast = result.forecast(7, interval=0.95)
```

The interval is calibrated from out-of-sample training-fold residuals and evaluated on holdout data.
It uses one global width, so it may not adapt to changing variance or distribution shift. The request
range is 0.50–0.999; `None` remains the default and classification rejects this option.

Binary classification probabilities use training-only sigmoid calibration by default. Set
`probability_calibration="isotonic"` for a more flexible, data-hungry method or `"off"` to preserve
raw estimator probabilities. Holdout `log_loss`, `brier_score` and
`result.chart("probability_calibration")` provide reliability evidence; they are not guarantees under
production drift.

### Drift monitoring

```python
drift = result.check_drift(current_data, threshold=0.20)
print(drift.status, drift.drifted_features)
drift.chart().to_json()
```

ML Prism computes PSI from summarized numeric quantiles, proportions, missingness and SHA-256 hashes of
frequent categories. It does not retain training rows or plain categorical values. Forecasting time
columns are excluded. PSI is an operational signal rather than proof of performance degradation or a
reason to retrain automatically.

See the complete English [API reference](docs/en/API.md) for every parameter and default.

### Forecasting

Forecasting requires a numeric target and a separate time column. ML Prism sorts timestamps, holds out
the newest rows and uses `TimeSeriesSplit`; it never randomly mixes past and future observations.

```python
result = learn(
    sales,
    "demand",
    config=LearnConfig(task="forecasting", time_column="date"),
)

result.chart("forecast")
future = result.forecast(7)  # when time is the only required future feature
```

When the model uses exogenous features, pass their actual future values:

```python
future = result.forecast(7, future_data=future_features)
```

ML Prism rejects missing, invalid or duplicate timestamps. This release supports one row per timestamp
and one series at a time; grouped forecasting and prediction intervals remain future work. If a
regular frequency cannot be inferred, pass `frequency` to `forecast()`.

## Report options

```python
analysis.report(
    "ml-prism-report.html",  # optional; this is the default path
    language="en",  # optional; default is pt-BR
    theme="dracula",  # optional; default is light
    open_browser=False,  # optional; default is False
)
```

The self-contained report supports light and Dracula themes, responsive Plotly resizing, horizontal
scrolling for wide projections, print rules, reduced-motion preferences and escaped dataset text.

## Quality and dependency updates

Weekly Dependabot proposals keep dependencies visible and current. Every proposal must pass the Python
version matrix, unit/property/integration tests, linting, source security scanning and dependency
auditing before it can be accepted. Run the same commands listed in the Portuguese quality section.

CI requires at least 98% combined line and branch coverage. The current suite reaches 100% for both;
this measurement complements, but does not replace, stress, security and statistical-validity tests.

See the English [architecture](docs/en/ARCHITECTURE.md) and
[testing strategy](docs/en/TESTING.md). Please read [SECURITY.md](SECURITY.md) before reporting a
vulnerability. The first-release evidence is recorded in
[Release 0.1.0 validation](docs/en/RELEASE_VALIDATION_0.1.0.md).

See the bilingual [changelog](CHANGELOG.md). Future releases and tags continue to require the
maintainer's explicit decision.
