"""Etapa 5: gera o relatório técnico (../relatorio/index.html) a partir dos resultados. Todos os números vêm dos arquivos em resultados/ e dados/processados/, para evitar erros de transcrição. Uso: python gerar_relatorio.py (depois de analisar.py e sensibilidade.py) """ import html import platform from importlib.metadata import version import pandas as pd from analisar import CAPITAIS, CRITERIO, ENTORNO_KM, POLO from config import ANOS, AUXILIARES, FAIXAS, GRUPOS, PROCESSADOS, RESULTADOS, RAIZ SAIDA = RAIZ.parent / "relatorio" / "index.html" VERSAO = "1.1" DATA = "28 de setembro de 2026" # Datas de publicação dos arquivos do SIM no FTP do DATASUS (listagem de 27/09/2026) VERSOES_SIM = { 2020: "31/03/2022", 2021: "28/04/2023", 2022: "21–22/12/2023", 2023: "19/12/2024 (alguns estados em 26/12/2024 e 21/01/2025)", 2024: "23/12/2025", } def br(x, casas=2): if pd.isna(x): return "—" s = f"{x:,.{casas}f}" return s.replace(",", "X").replace(".", ",").replace("X", ".") def inteiro(x): return f"{int(x):,}".replace(",", ".") def tabela(cab, linhas, classe=""): th = "".join(f"
Estudo exploratório — não são conclusões. Este relatório descreve um estudo ecológico e descritivo, ainda não revisado por especialistas independentes. Os sinais são hipóteses para avaliação. Eles não indicam causa, não permitem estimar o risco de uma pessoa específica e não mudam nenhuma recomendação médica. Versão {VERSAO} · {DATA}.
Pergunta: em quais municípios a mortalidade por câncer, de 2020 a 2024, ficou acima do esperado para a idade e o sexo de sua população, com evidência estatística forte? Desenho: estudo ecológico, descritivo e exploratório, com o município como unidade de análise. Desfecho: óbito com câncer como causa básica (campo CAUSABAS da declaração de óbito). Cada óbito é atribuído ao município de residência (campo CODMUNRES), não ao de ocorrência.
Grupos auxiliares, usados só para qualidade e contexto: todas as causas ({AUXILIARES['todas_causas'][0][0]}–{AUXILIARES['todas_causas'][0][1]}) e causas mal definidas ({AUXILIARES['mal_definidas'][0][0]}–{AUXILIARES['mal_definidas'][0][1]}). A comparação usa os três primeiros caracteres da causa básica. Faixas etárias: {", ".join(FAIXAS)} anos. Idade: unidade 0–3 do campo IDADE (menos de 1 ano) = 0; unidade 4 = anos; unidade 5 = 100 anos ou mais.
Foram mantidas {inteiro(total)} declarações de óbito de todas as causas, das quais {inteiro(cancer)} com câncer (C00–C97) como causa básica e {inteiro(mal)} ({br(100 * mal / total, 1)}%) com causa mal definida. Foram excluídas {inteiro(excl)} declarações ({br(100 * excl / (total + excl), 2)}% do total), por falta de informação necessária para a padronização:
{tabela(["Motivo", "Declarações"], [ ["Município de residência ignorado ou inválido (código com 6 dígitos terminado em 0000, ou ausente)", inteiro(desc.get("municipio_ignorado", 0))], ["Sexo ignorado", inteiro(desc.get("sexo_ignorado", 0))], ["Idade ignorada", inteiro(desc.get("idade_ignorada", 0))]])}As exclusões são aplicadas nessa ordem, a todas as causas. Não há imputação de valores ausentes. Todos os 5.570 municípios do Censo 2022 entram na análise, inclusive os com zero óbitos em um grupo.
Óbitos esperados (padronização indireta). Para cada grupo e referência (Brasil ou a UF do município), a taxa de referência é rs,a = óbitoss,a / pessoa-anoss,a, por sexo s e faixa etária a. Os esperados do município i são Ei = Σs,a rs,a × Pi,s,a × 5, em que P é a população do Censo 2022. Por construção, a soma dos esperados é igual à soma dos observados em cada referência.
RMP = Oi / Ei, com intervalo de confiança exato de 95% (método de Garwood, pela distribuição qui-quadrado). Teste: Poisson unilateral, p = P(X ≥ Oi | Ei). Correção para múltiplas comparações: Benjamini-Hochberg (FDR) aplicada dentro de cada tipo de câncer, sobre os 5.570 municípios. A correção sobre todos os 13 tipos juntos foi testada na sensibilidade (cenário C).
Suavização bayesiana empírica (Marshall, 1991): modelo Poisson-Gama, com priori Gama estimada pelo método dos momentos, uma por grupo e referência. RMP suavizada = (O + α) / (E + β), e a probabilidade posterior de RMP > 1 vem da distribuição Gama(O + α, E + β). Por isso, a RMP suavizada costuma ser menor que a divisão direta O / E em municípios pequenos: em {ex.municipio} (esôfago), por exemplo, {ex.observados} / {br(ex.esperados_uf)} = {br(ex.rmp_uf)} sem suavização e {br(ex.rmp_suav_uf)} com suavização, com IC 95% de {br(ex.ic95_inf_uf)} a {br(ex.ic95_sup_uf)} para a RMP sem suavização.
{prio_tab}Critérios de sinal (referência: a UF do município): q < {br(CRITERIO['q_max'])}; P(RMP > 1) > {br(CRITERIO['prob_min'])}; RMP suavizada ≥ {br(CRITERIO['rmp_min'], 1)}; pelo menos {CRITERIO['obitos_min']} óbitos observados. A referência estadual reduz, mas não elimina, diferenças regionais de diagnóstico e registro.
Critérios geográficos exploratórios. Cada sinal recebe um contexto: capital ({len(CAPITAIS)} capitais); entorno de capital (centro aproximado do município a até {ENTORNO_KM} km do centro de uma capital); polo de tratamento (pelo menos {POLO['nao_residentes_min']} óbitos por câncer de não residentes ocorridos no município e pelo menos {int(100 * POLO['razao_min'])}% dos óbitos por câncer de seus residentes). Os demais aparecem como "após critérios geográficos". Os limiares foram escolhidos de forma exploratória, sem validação externa. Esses critérios não demonstram que os vieses foram removidos e podem excluir excessos reais. As diretrizes do CDC ressaltam que escolhas geográficas podem criar ou ocultar padrões e exigem interpretação especializada. Por isso, os limiares foram variados na sensibilidade.
{len(sinais)} sinais em {sinais['cod_ibge'].nunique()} municípios: {ctx.get('capital', 0)} em capitais, {ctx.get('entorno de capital', 0)} no entorno de capitais, {ctx.get('polo de tratamento', 0)} em polos de tratamento e {ctx.get('prioritário', 0)} após os critérios geográficos exploratórios. A contagem por grupo está na tabela da seção 3.
Cada cenário muda uma escolha do método e mantém as demais. "Em comum" conta os pares município–câncer que permanecem após os critérios geográficos tanto no cenário quanto na análise principal. No cenário D, a população por idade e sexo de 2022 é reescalada pelo total estimado de cada ano. As estimativas de 2020 e 2021 foram feitas antes do Censo e ficam acima dele, então esse cenário testa a sensibilidade à população, e não uma população "correta".
{sens_tab}{n_estaveis} dos {len(est)} municípios com sinal após os critérios geográficos permanecem em todos os cenários de sensibilidade. A RMP por período usa os esperados em relação ao Brasil divididos proporcionalmente ao número de anos. Isto é uma checagem de estabilidade, não uma validação independente: os municípios foram selecionados com os cinco anos juntos, então o excesso tende a aparecer nos dois períodos por construção. Uma validação independente exigiria dados de outro período, não usados na seleção, ou outra fonte, como registros de incidência.
{est_tab}A IA (Claude, da Anthropic) foi usada como assistente de programação e de redação: escreveu o código a partir das especificações, ajudou a explorar os dados e a revisar os textos, sempre com revisão humana. A análise é epidemiológica e estatística clássica (padronização indireta, testes de Poisson, FDR e suavização bayesiana empírica). Nenhum modelo de aprendizado de máquina foi treinado, ajustado ou avaliado nesta fase. Para o futuro piloto clínico com modelos preditivos, o relato seguirá a diretriz TRIPOD+AI.
O código completo roda em Python {platform.python_version()} ({pacotes}). Ordem:
baixar.py → preparar.py → analisar.py → sensibilidade.py →
gerar_mapa.py → gerar_relatorio.py. Os resultados completos estão em
municipios_rmp.csv, sinais.csv,
sensibilidade.csv e parametros_suavizacao.csv.
Os arquivos do DATASUS podem ser republicados com correções; por isso as datas da seção 2 importam.