Metadata-Version: 2.5
Name: inputfit
Version: 0.7.0
Summary: Análise de dados de entrada para modelos de simulação, com veredito honesto
Project-URL: Homepage, https://inputfit.streamlit.app/
Project-URL: Repository, https://github.com/genoadev/analise-dados-de-entrada
Author-email: Genoa Soluções <contato@genoads.com.br>
License: # Licença do inputfit
        
        O inputfit é distribuído sob **licenciamento dual**:
        
        1. **Uso não comercial** — gratuito, sob a PolyForm Noncommercial License
           1.0.0 (texto integral abaixo). Cobre ensino, pesquisa, uso pessoal e
           avaliação: professor em disciplina, aluno em exercício, pesquisador em
           artigo, engenheiro testando a ferramenta antes de decidir.
        
        2. **Uso comercial** — mediante licença comercial da Genoa Soluções.
           Cobre o uso no trabalho: análise de dados de entrada em projeto de
           simulação, consultoria, produto ou operação de empresa. Termos e preço
           sob consulta: **contato@genoads.com.br** · genoads.com.br. A resposta
           padrão para um engenheiro individual é simples e rápida — escreva.
        
        Em caso de dúvida sobre qual lado se aplica ao seu uso, escreva antes de usar.
        
        ---
        
        # PolyForm Noncommercial License 1.0.0
        
        <https://polyformproject.org/licenses/noncommercial/1.0.0>
        
        ## Acceptance
        
        In order to get any license under these terms, you must agree to them as both strict obligations and conditions to all your licenses.
        
        ## Copyright License
        
        The licensor grants you a copyright license for the software to do everything you might do with the software that would otherwise infringe the licensor's copyright in it for any permitted purpose.  However, you may only distribute the software according to [Distribution License](#distribution-license) and make changes or new works based on the software according to [Changes and New Works License](#changes-and-new-works-license).
        
        ## Distribution License
        
        The licensor grants you an additional copyright license to distribute copies of the software.  Your license to distribute covers distributing the software with changes and new works permitted by [Changes and New Works License](#changes-and-new-works-license).
        
        ## Notices
        
        You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms or the URL for them above, as well as copies of any plain-text lines beginning with `Required Notice:` that the licensor provided with the software.  For example:
        
        > Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
        
        ## Changes and New Works License
        
        The licensor grants you an additional copyright license to make changes and new works based on the software for any permitted purpose.
        
        ## Patent License
        
        The licensor grants you a patent license for the software that covers patent claims the licensor can license, or becomes able to license, that you would infringe by using the software.
        
        ## Noncommercial Purposes
        
        Any noncommercial purpose is a permitted purpose.
        
        ## Personal Uses
        
        Personal use for research, experiment, and testing for the benefit of public knowledge, personal study, private entertainment, hobby projects, amateur pursuits, or religious observance, without any anticipated commercial application, is use for a permitted purpose.
        
        ## Noncommercial Organizations
        
        Use by any charitable organization, educational institution, public research organization, public safety or health organization, environmental protection organization, or government institution is use for a permitted purpose regardless of the source of funding or obligations resulting from the funding.
        
        ## Fair Use
        
        You may have "fair use" rights for the software under the law. These terms do not limit them.
        
        ## No Other Rights
        
        These terms do not allow you to sublicense or transfer any of your licenses to anyone else, or prevent the licensor from granting licenses to anyone else.  These terms do not imply any other licenses.
        
        ## Patent Defense
        
        If you make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
        
        ## Violations
        
        The first time you are notified in writing that you have violated any of these terms, or done anything with the software not covered by your licenses, your licenses can nonetheless continue if you come into full compliance with these terms, and take practical steps to correct past violations, within 32 days of receiving notice.  Otherwise, all your licenses end immediately.
        
        ## No Liability
        
        ***As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.***
        
        ## Definitions
        
        The **licensor** is the individual or entity offering these terms, and the **software** is the software the licensor makes available under these terms.
        
        **You** refers to the individual or entity agreeing to these terms.
        
        **Your company** is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization.  **Control** means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise.  Control can be direct or indirect.
        
        **Your licenses** are all the licenses granted to you for the software under these terms.
        
        **Use** means anything you do with the software requiring one of your licenses.
License-File: LICENSE.md
Keywords: aic,anylogic,censored-data,discrete-event-simulation,distribution-fitting,input-analysis,simulation
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Manufacturing
Classifier: Intended Audience :: Science/Research
Classifier: Natural Language :: Portuguese (Brazilian)
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.11
Requires-Dist: numpy>=1.26
Requires-Dist: pandas>=2.0
Requires-Dist: scipy>=1.11
Provides-Extra: app
Requires-Dist: openpyxl>=3.1; extra == 'app'
Requires-Dist: plotly>=5.20; extra == 'app'
Requires-Dist: streamlit>=1.40; extra == 'app'
Provides-Extra: dev
Requires-Dist: openpyxl>=3.1; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Description-Content-Type: text/markdown

# inputfit

*English: [README.en.md](README.en.md) · Español: [README.es.md](README.es.md)*

> **English:** inputfit speaks English — web app at
> [inputfit.streamlit.app/?lang=en](https://inputfit.streamlit.app/?lang=en),
> CLI with `--lang en`.
> **Español:** inputfit habla español — aplicación web en
> [inputfit.streamlit.app/?lang=es](https://inputfit.streamlit.app/?lang=es),
> CLI con `--lang es`.

Análise de dados de entrada para modelos de simulação. Diz qual distribuição
descreve os dados e, principalmente, **quando os dados não escolhem nenhuma**.

```
$ python -m inputfit inputfit/examples/ships_demo.csv --col ETA

  ATENÇÃO: O horário 00:01:00 aparece 22 vezes em 110 registros de 'ETA'. Isso
           não é um horário, é o preenchimento de quem sabia a data e não a
           hora. Esses registros valem 'algum momento daquele dia', e é assim
           que serão tratados.

Empate técnico entre exponencial, gama e Weibull. Os dados não escolhem uma
delas.

  distribuição           AIC     ΔAIC
  exponencial         1421.0     0.00   empatada
  gama                1422.9     1.86   empatada
  Weibull             1422.9     1.92   empatada
  lognormal           1434.8    13.74   descartada

  Recomendada: exponencial  (1 parâmetro estimado)

  Para o AnyLogic:
    // exponencial de 'ETA': 109 observações, 109 como faixa
    // unidade: h   |   AIC 1421.0   |   1 parâmetro(s) estimado(s)
    exponential(0.0138933, 0)
```

A base do exemplo acompanha o pacote e é **100% sintética** — gerada por
`scripts/gera_demo.py`, sem nenhuma linha derivada de dado real, reproduzindo de
propósito as degenerações que a ferramenta existe para tratar (sentinela de
horário, intervalo zero, empate técnico, piso rígido). `tests/test_demo.py`
garante que uma regeneração não perde nenhuma delas.

## Por que existe

Ferramenta de ajuste de distribuição costuma entregar **um vencedor com um número
de confiança ao lado**. É esse comportamento que produz o erro: a ferramenta
projeta certeza que os dados não sustentam.

Medido numa base portuária real de 110 chegadas:

| ferramenta | critério | vencedor |
|---|---|---|
| script original | p-valor de Kolmogorov-Smirnov | `expon` |
| `distfit` | erro sobre o histograma | `expon` |
| `fitter` | erro quadrático | `weibull_min` |
| `fitter` (coluna AIC) | AIC | `gamma` |
| **inputfit** | **AIC com verossimilhança censurada** | **empate de três** |

Quatro respostas diferentes, zero avisos. E as três primeiras compartilham o mesmo
defeito estatístico: p-valor de KS com parâmetro estimado da própria amostra não
tem validade. Medido, o teste ingênuo rejeita em 0,7% das vezes quando deveria
rejeitar em 5% — ele **aceita ajuste ruim**, que para simulação é o erro pior
porque passa despercebido.

## Quatro coisas que ele faz e os outros não

**Declara empate.** Diferença de AIC abaixo de 2 não sustenta preferência.
Coroar a de menor AIC nessa faixa é inventar precisão que a amostra não tem.

**Trata registro arredondado como arredondado.** Um timestamp anotado como
`01/03/2018 00:01` quando só se sabia a data não vale 00:01, vale "algum momento
daquele dia". Cada observação entra como uma faixa e contribui `F(b) − F(a)` em
vez da densidade pontual. A alternativa óbvia — descartar os intervalos de valor
zero — funde dois eventos num só e **derruba a taxa de chegada em 8,2%**. Num
estudo de capacidade de berço isso é a diferença entre recomendar e não
recomendar um investimento.

**Avisa quando a coluna é saída do modelo.** Um piso rígido muito acima de zero é
assinatura de restrição de capacidade. Atracação de navio tem piso porque o berço
precisa desocupar, e berço ocupado é fila, que o simulador calcula. Ajustar uma
distribuição nela e realimentar o modelo assa a capacidade atual dentro da
premissa de chegada, e o modelo perde a capacidade de responder à pergunta para a
qual existe.

**Confere a ordem física entre colunas.** Chegada posterior à atracação é
impossível, e nenhuma estatística pega: distribuição ajustada a carimbo trocado
ajusta bem e mente.

## E o p-valor?

O critério do livro-texto de graduação é p-valor, e a troca por AIC não é um
abandono: os dois saem da mesma verossimilhança máxima e respondem perguntas
diferentes. O teste de aderência pergunta se **uma** distribuição pode ser
rejeitada, não ordena candidatas, e o poder dele cresce com `n` — com muitos dados
rejeita tudo, com poucos não rejeita nada. AIC compara as candidatas entre si,
com preço pela complexidade.

Para modelos aninhados que diferem por um parâmetro — a exponencial é a gama com
forma fixada em 1 — as duas escalas são a mesma conta: `ΔAIC = D − 2`, com `D` a
estatística da razão de verossimilhanças. Traduzido: preferir o modelo maior só
pelo AIC equivale a aceitar `p < 0,157`, bem mais permissivo que os 0,05 do
costume. É por isso que declarar empate abaixo de ΔAIC 2 importa — esse corte
corresponde a `p < 0,046`. Entre famílias não aninhadas (gama contra lognormal)
não existe p-valor nenhum, e o AIC compara assim mesmo.

O teste de aderência continua disponível para a pergunta que o AIC não responde,
que é se a primeira colocada presta em termos absolutos: o botão **rodar teste de
aderência** na interface web roda `gof_censored`, o Kolmogorov-Smirnov calibrado
por bootstrap paramétrico com cada réplica sofrendo a mesma perda de precisão dos
dados observados. É a versão do teste que não tem o defeito descrito acima.

## Como usar

**Sem instalar nada:** a interface web roda em
[inputfit.streamlit.app](https://inputfit.streamlit.app/) — instância pública;
não envie dados operacionais confidenciais. A interface fala português,
inglês e espanhol (seletor na barra lateral, ou `?lang=en` / `?lang=es` na
URL).

**Instalando (Python 3.11+):**

```bash
pip install inputfit                 # motor + linha de comando
inputfit planilha.csv --col ETA

pip install 'inputfit[app]'          # com a interface web
inputfit-app
```

O relatório de premissa (HTML autocontido, 1-2 páginas, para anexar e imprimir):

```bash
inputfit planilha.csv --col ETA --report relatorio.html
```

**Para desenvolver** (clone do repositório, com [uv](https://docs.astral.sh/uv/)):

```bash
uv sync                                   # motor + casca web
uv run python -m inputfit planilha.csv --col ETA
uv run streamlit run app.py
uv run --extra dev pytest                 # a suíte
```

Opções úteis (os nomes em português continuam aceitos como sinônimos):

```bash
--list-cols                          lista as colunas e sai
--list-sheets                        lista as abas do Excel
--sheet "Base Navios"                escolhe a aba
--kind duration                      duração de serviço (permite piso positivo)
--dists expon gamma                  restringe as candidatas
--sequence ETA ATR ICA TCA DTR       confere a ordem física dos carimbos
--report relatorio.html              grava o relatório de premissa
--lang en                            idioma da saída (pt, en ou es)
```

Código de saída: `0` ajustou, `1` os dados não permitem ajuste, `2` erro de uso.
A distinção entre 1 e 2 importa: dado que não permite ajuste é **resultado** da
ferramenta, não erro de invocação.

Como biblioteca:

```python
from inputfit import analyze

r = analyze(planilha["ETA"], "ETA")
r.verdict.headline          # 'Empate técnico entre gama, Weibull e exponencial...'
r.verdict.recommended.label # 'exponencial'
r.verdict.caveats           # ressalvas que devem aparecer ACIMA do resultado
```

`analyze` devolve sempre um `AnalysisResult`, nunca `None`. Dado não ajustável é
resultado esperado e valioso — é o que a ferramenta existe para detectar.

## Arquitetura

```
  planilha
      |
      v
  +----------+   DataFrame + relatorio de parsing
  |  io.py   |   (linha vazia != valor nao parseavel)
  +----------+
      |
      v
  +--------------+   avisos + resolucao POR OBSERVACAO
  | diagnose.py  |   sentinela de horario, piso rigido,
  +--------------+   ordem fisica entre colunas
      |
      | (veto) --------> verdict.py  "nao ajustavel, eis o porque"
      v
  +----------+   verossimilhanca censurada + AIC + aderencia
  |  fit.py  |   SO NUMEROS, nenhuma opiniao
  +----------+
      |
      v
  +-------------+   TODOS os limiares vivem aqui
  | verdict.py  |   dAIC<2, parcimonia, veto sobrepoe AIC
  +-------------+
      |
      v
  +------------+   escala -> taxa, por distribuicao
  | export.py  |
  +------------+
```

`specs.py` é o registro: cada distribuição declara **uma vez** a restrição de
ajuste, as acumuladas em forma fechada e a parametrização do simulador de
destino. Sem isso, alguém atualizaria uma e esqueceria a outra, e o validador
testaria um modelo diferente do que foi ajustado — sem erro nenhum.

Três fronteiras têm teste que falha se vazarem: limiar de decisão só existe em
`verdict.py`, `diagnose.py` não expõe política de limpeza, e as duas interfaces
não decidem sobre exportação por conta própria.

## Testes

```bash
uv run pytest                  # 522 testes, ~60 s
uv run pytest -m lento         # calibração estatística, minutos
```

A calibração mede a taxa de erro tipo I com verdade conhecida por construção:
quando os dados vêm da distribuição testada, o teste precisa rejeitar em α das
vezes. Medido com 400 simulações × 199 réplicas:

| dist | @0,05 | @0,10 | @0,01 |
|---|---|---|---|
| `expon` | 0,0300 | 0,0725 | 0,0025 |
| `gamma` | 0,0475 | 0,1075 | 0,0150 |
| `weibull_min` | 0,0475 | 0,1025 | 0,0075 |
| `lognorm` | 0,0275 | 0,0750 | 0,0000 |

Todas dentro de ±0,033 do nominal. É essa medição que separa "eu digo que a
ferramenta é honesta" de "eu provo".

## Alvos de exportação e procedência dos mapeamentos

O bloco de parâmetros sai para quatro alvos (`--target anylogic|excel|python|simul8`)
ou num **formato declarado por você** (`--template "EXPO({media})"`), com
disciplina de verificação POR ALVO:

- **AnyLogic** — as quatro exportações (`exponential`, `gamma`, `weibull`,
  `lognormal`) estão **conferidas contra a documentação**, e a lognormal também
  empiricamente: `lognormal(0.1, 2.0, 0)` amostrada centenas de vezes deu mediana
  ~1,1 (= e^0,1), o que só é possível com a assinatura `lognormal(mu, sigma, min)`.
- **Python** — conferível por construção: emite o próprio `scipy.stats` que o
  motor ajustou; a suíte avalia a string emitida e compara a CDF com o ajuste.
- **Excel** — fórmulas de CDF inversa de livro-texto, espelhadas função a função
  e conferidas contra a `ppf` do scipy na suíte.
- **Simul8** — a documentação pública **não publica** as parametrizações, então
  todos os mapeamentos nascem `verified=False` e ficam retidos atrás de
  `--allow-unverified`, com o protocolo de conferência de 30s na nota.
- **Formato declarado** — não há documentação contra a qual conferir um formato
  que você declarou; no lugar da retenção, o bloco sai com um glossário dos
  campos usados (`{beta}` é ESCALA, não taxa — o erro caro do domínio).

A nota de procedência completa de cada mapeamento vive em `inputfit/specs.py`.
O mecanismo de retenção continua no produto: mapeamento não conferido não sai
em silêncio, em nenhum alvo.

## Dados

`data/` está no `.gitignore` e nunca entra no histórico: são movimentações
portuárias reais. Os testes usam `tests/fixtures/`, que preserva a estrutura sem
a identificação. Ver `tests/fixtures/README.md`.

## Licença

Licenciamento **dual** (ver [LICENSE.md](LICENSE.md)):

- **Uso não comercial** — gratuito, sob a PolyForm Noncommercial 1.0.0. Cobre
  ensino, pesquisa, uso pessoal e avaliação.
- **Uso comercial** — projeto de simulação, consultoria, produto ou operação
  de empresa exigem licença comercial da Genoa Soluções:
  **contato@genoads.com.br**. Resposta simples e rápida para engenheiro
  individual — escreva.
