Avaliação de severidade RELSA e previsão de ponto final humanitário
Visão geral
A avaliação de severidade em pesquisa animal é legalmente obrigatória e cientificamente essencial: ela orienta decisões de ponto final humanitário, e o monitoramento deficiente do bem-estar reduz a reprodutibilidade. A prática usual avalia cada variável isoladamente — perda de peso aqui, um escore clínico ali — o que dificulta determinar quão mal um animal individual está realmente.
Esta skill implementa dois procedimentos publicados que abordam isso:
- RELSA (Talbot et al., 2022) combina várias medidas de resultado em um único escore por animal por ponto no tempo, expresso em relação a um conjunto de referência de sofrimento conhecido. RELSA = 0 é a linha de base; RELSA = 1 significa que o animal atingiu o desvio máximo do conjunto de referência.
- foRcast (Lutscher et al., 2026) ajusta um modelo ARIMA à trajetória RELSA de um animal individual e prevê o próximo escore com um intervalo de predição de 95%, para que animais caminhando para um ponto final humanitário possam ser identificados antes de chegar lá. A estimativa de densidade kernel na escala RELSA fornece zonas candidatas de atenção e perigo para interpretação.
O objetivo é o refinamento: dar atenção mais cedo a animais em risco e evitar eutanasiar animais que se recuperariam. Ambos os procedimentos são auxílios à avaliação de severidade, não regras de decisão — veja Limitações.
Quando usar esta skill
- Combinar perda de peso, temperatura, escore clínico, biomarcadores ou telemetria em um único escore de severidade por animal
- Perguntar quais animais em uma coorte estão em risco de atingir um ponto final humanitário, ou prever o escore de severidade em um ponto futuro
- Comparar severidade entre grupos de tratamento, intervenções ou modelos animais em uma escala relativa comum
- Definir limites ou zonas em uma escala de severidade a partir dos dados
- Escrever a seção de avaliação de severidade de um relatório de bem-estar animal, uma análise de refinamento/3Rs, ou uma aplicação sob a Diretiva 2010/63/UE da União Europeia
Para previsão geral de séries temporais que não sejam escores de severidade, use timesfm-forecasting ou statsmodels. Para desenho experimental e tamanho amostral, use experimental-design e statistical-power.
Instalação
uv pip install "numpy>=1.26" "pandas>=2.0" "scipy>=1.11" "statsmodels>=0.14" matplotlib
relsa_score.py e kde_thresholds.py necessitam apenas de numpy/pandas/scipy; statsmodels é necessário para previsão e matplotlib apenas para figuras.
Formato dos dados
Uma linha por animal por ponto no tempo, em um CSV:
| id | treatment | condition | day | temp | weight | score | il6 |
|---|---|---|---|---|---|---|---|
| M01 | treated | endpoint | -1 | 37.15 | 25.17 | 0 | 35.1 |
| M01 | treated | endpoint | 0 | 37.26 | 25.25 | 0 | 39.5 |
| M01 | treated | endpoint | 1 | 35.83 | 23.12 | 4 | 162.0 |
ide uma coluna de tempo (day,time,hour, …) são obrigatórios;treatmenteconditionsão rótulos opcionais usados para agrupamento e seleção do conjunto de referência.- O tempo pode ser dias, horas ou minutos — apenas mantenha-o monotônico por animal. A convenção do RELSA codifica o ponto de tempo da linha de base como
-1. - Uma linha por animal por ponto no tempo. Média da telemetria horária para um valor por intervalo primeiro (os modelos publicados calculam a média da frequência cardíaca, VFC e temperatura, e somam a atividade).
- Deixe medições faltantes vazias. Elas são removidas do escore, nunca imputadas — um valor faltante tratado como "sem desvio" tendencia a severidade para baixo.
assets/example_cohort.csv é uma pequena coorte sintética (6 camundongos, 9 dias, temperatura, peso corporal, um escore clínico de 0–8 e um biomarcador semelhante a IL-6) usado por todos os comandos abaixo, então cada um pode ser executado como escrito.
As quatro decisões que determinam o resultado
Tome-as explicitamente e escreva-as nos métodos. Nada mais sobre o procedimento importa tanto.
1. Direcionalidade — quais variáveis aumentam com a piora? A queda é o padrão (peso corporal, atividade, ingestão de alimentos, escavação, corrida em roda). Variáveis que sobem devem ser declaradas como --turned: escores clínicos, biomarcadores inflamatórios, febre, taquicardia. Errar isso faz com que a variável não contribua em nada, silenciosamente, porque desvios na direção "errada" são limitados a zero. A temperatura corporal depende do modelo — cai em sepse e endotoxemia, sobe em modelos de febre. Nada nos dados pode resolver isso para você: no modelo de sepse publicado, a atividade oscila legitimamente mais acima da linha de base do que abaixo, então apenas uma variável que nunca uma vez se move na direção declarada é detectável, e build_reference() avisa exatamente sobre esse caso.
2. O conjunto de referência — relativo a quê? Escores RELSA não significam nada sem ele. Use o grupo que se presume carregar a maior carga em seu modelo (os estudos publicados usam o grupo de maior dose ou que atinge o ponto final). Um conjunto de referência muito leve empurra todos os escores acima de 1; muito severo comprime tudo em direção a 0. Salve-o com --save-reference e reutilize-o com --load-reference para que coortes posteriores permaneçam na mesma escala.
3. Escores com uma linha de base zero. Um escore clínico de 0 em um animal saudável não pode ser normalizado por razão — 0/0 é indefinido. Use --score-scale score=8 para mapear a escala do escore (saudável → 100%, pior possível → 200%), o que também o marca como virado. Este mapeamento é uma escolha de modelagem sobre quanto um ponto de escore vale em relação a um por cento do peso corporal; declare-a. A alternativa é manter o escore fora do RELSA e usá-lo como um critério de ponto final independente.
4. Quais variáveis são medidas ao longo de todo o período. Como o escore calcula a média sobre as variáveis disponíveis, uma variável que aparece ou desaparece no meio da trajetória move o escore por si só. Nos dados de sepse publicados, adicionar peso corporal — registrado apenas no dia da eutanásia — reduz o escore final desse animal de 0,93 para 0,83 sem razão biológica. relsa_scores() avisa quando a composição muda; use as variáveis presentes ao longo de todo o período.
Fluxo de trabalho
Etapa 1 — calcular escores RELSA
python scripts/relsa_score.py assets/example_cohort.csv \
--variables weight,temp,score,il6 \
--normalize weight,temp,il6 \
--turned il6 \
--score-scale score=8 \
--baseline-time -1 \
--reference-group condition=endpoint \
--save-reference reference.json \
--out relsa_scores.csv
O modelo de referência é ecoado para que a escala seja auditável:
reference model: assets/example_cohort.csv [condition=endpoint]
animals=2 rows=18 baseline_time=-1.0
variable turned max reached max delta
weight no 82.40 17.60
temp no 92.79 7.21
score yes 187.50 87.50
il6 yes 797.72 697.72
relsa_scores.csv contém o peso de cada variável junto com o escore, que é o que torna o escore explicável — aqui M01 se deteriorando até seu ponto final, M03 atingindo o pico no dia 3 e se recuperando:
id time weight temp score il6 n_vars relsa
M01 1 0.46 0.49 0.57 0.52 4 0.51
M01 3 0.84 0.76 1.00 0.89 4 0.88
M01 5 1.00 1.00 1.00 1.00 4 1.00
M03 3 0.56 0.44 0.57 0.54 4 0.53
M03 5 0.35 0.26 0.43 0.32 4 0.35
M03 7 0.12 0.06 0.14 0.11 4 0.11
Um peso de 1,00 significa que aquela variável atingiu o máximo da referência; n_vars é quantas variáveis entraram no escore naquele ponto no tempo.
A mesma coisa a partir do Python, quando você precisa dos objetos:
import sys; sys.path.insert(0, "scripts")
from _common import read_relsa_table, score_to_percent
from relsa_score import prepare, build_reference, relsa_scores
frame = read_relsa_table("assets/example_cohort.csv")
frame["score"] = score_to_percent(frame["score"], max_score=8) # escore clínico 0-8
VARS, TURNED = ["weight", "temp", "score", "il6"], ["score", "il6"]
prepared = prepare(frame, normalize=["weight", "temp", "il6"], baseline_time=-1)
reference = build_reference(prepared[prepared.condition == "endpoint"],
variables=VARS, turned=TURNED, baseline_time=-1,
label="animais que atingem ponto final")
scores = relsa_scores(prepared, reference)
Etapa 2 — prever o ponto final
Treine em tudo até o ponto no tempo antes do ponto final, prediga o escore no ponto final e avalie a predição:
python scripts/forecast_relsa.py relsa_scores.csv \
--animals M01,M02 --endpoints M01=5 --endpoints M02=6 \
--group-col condition --plot-dir figs --endpoint-line 1.0
id time predicted lower upper model actual
M01 5.0 0.932585 0.670443 1.194728 ARIMA(1,1,0) 1.00
M02 6.0 0.955696 0.748309 1.163084 ARIMA(1,1,0) 0.94
group id model n rmse picp mpiw
endpoint M01 ARIMA(1,1,0) 1 0.0674 100.0 0.524
endpoint M02 ARIMA(1,1,0) 1 0.0157 100.0 0.415
endpoint -- endpoint -- 2 0.0489 100.0 0.470
OVERALL 2 0.0489 100.0 0.470
Relate todas as três métricas juntas. RMSE é a precisão pontual, PICP a porcentagem de valores reais dentro do intervalo e MPIW a largura média do intervalo em unidades RELSA — um modelo pode atingir PICP = 100% tornando o intervalo tão amplo que não diz nada, que é exatamente o que a linha de câncer pancreático do artigo (PICP 100%, MPIW 7,35, ou seja, 735% da faixa RELSA) mostra.
Para monitoramento ao vivo, preveja um passo à frente em cada ponto no tempo:
python scripts/forecast_relsa.py relsa_scores.csv --mode rolling --animals M03
Duas coisas a saber antes de confiar em uma previsão:
- A interpolação está ativada por padrão (
--interpolate-step 0.1), porque uma medição por dia é muito esparsa para ARIMA. Ela compra seleção de modelo utilizável e intervalos mais estreitos ao custo de incerteza honesta. Defina--interpolate-step 0quando a frequência de medição permitir. - ARIMA não pode prever um precipício. Ele assume estacionariedade e linearidade, então um colapso abrupto nas últimas horas antes de um ponto final não será previsto a partir de uma trajetória anterior suave — o próprio caso de falha do artigo. Aja com base no limite superior do intervalo e nunca deixe que uma previsão baixa substitua um animal que parece doente.
Etapa 3 — contextualizar o escore com zonas de severidade
python scripts/kde_thresholds.py relsa_scores.csv \
--group treatment=treated --n-thresholds 2 --plot zones.png --json zones.json
KDE on 33 RELSA scores (bandwidth = 0.1502)
candidate thresholds (density minima): 0.703
density modes: 0.264, 0.866
normal [0.000, 0.703) n=25 (75.8%)
danger >= 0.703 n=8 (24.2%)
Os limites são os mínimos da densidade do escore — os vales esparsos entre aglomerados de escores. Inclua animais de ponto final, sobreviventes e controles simulados: as zonas devem separar esses estados, então todos eles devem estar representados.
Verifique a largura de banda antes de acreditar em um limite. Nos dados de sepse publicados, esta implementação encontra mínimos em 0,355 e 0,655 (publicado: 0,337 e 0,643) — mas uma largura de banda 10% maior remove ambos os mínimos completamente. Execute a varredura em references/thresholds-and-zones.md e relate a varredura, não um par de números nus. Uma lista de limites vazia é uma resposta legítima: os escores formam um aglomerado e não há um local baseado em dados para cortar.
Limitações: declare estas ao relatar
- RELSA é um auxílio à avaliação de severidade, não um parâmetro decisivo. Um animal com escore RELSA baixo que mostre outros sinais de sofrimento ainda deve ser tratado adequadamente. Nenhum dos procedimentos é um preditor validado de morte.
- As zonas KDE não são graduações regulatórias de severidade. As categorias da Diretiva 2010/63/UE (não recuperação, leve, moderada, severa) são atribuídas prospectivamente por um processo diferente. O artigo é explícito de que seus limites "não devem ser confundidos com graduações regulatórias de severidade" e não são diretamente traduzíveis para elas.
- Os escores não são comparáveis entre conjuntos de referência ou modelos. RELSA é relativo por construção, e a pontuação clínica não é harmonizada entre laboratórios. Sempre relate o conjunto de referência junto com o escore.
- A evidência publicada é uma prova de conceito: 13 animais em sete modelos, cinco dessas linhas apoiadas em um ou dois animais. O RMSE geral de 0,069 e PICP de 96% vêm de 13 previsões de ponto final.
- Um escore subestimado é o erro perigoso, porque desencoraja a atenção e pode atrasar uma decisão de eutanásia, enquanto uma superestimativa meramente provoca cuidado extra.
Lista de verificação para relato
Uma análise de severidade é reproduzível apenas se tudo isso for declarado:
- Medidas de resultado, suas unidades e sua direcionalidade (quais foram viradas e por quê).
- O ponto ou janela de linha de base e quais variáveis foram normalizadas.
- Qualquer mapeamento de escore aplicado a variáveis ordinais, com sua escala.
- O conjunto de referência: quais animais, qual grupo, quantos e por que se presume que carregam a maior carga.
- Critérios de ponto final humanitário realmente aplicados no estudo, separadamente do escore RELSA.
- Para previsões: passo de interpolação, a ordem ARIMA selecionada por animal e RMSE, PICP e MPIW.
- Para limites: a largura de banda, o número de escores e uma varredura de sensibilidade da largura de banda.
- Versões de software e a declaração de que os limites são específicos do modelo e não graduações regulatórias.
Armadilhas comuns
- Direcionalidade errada — uma variável crescente não listada em
--turnedcontribui exatamente zero, silenciosamente, e nenhum aviso é possível a menos que ela nunca caia uma vez. Verifique você mesmo a tabela do modelo de referência:max reacheddeve estar abaixo de 100 para uma variável decrescente e acima de 100 para uma virada, emax deltadeve ter um tamanho plausível para aquela medida. - Normalizar uma porcentagem duas vezes —
bwc [%]e escores mapeados já estão na escala percentual; passá-los para--normalize[truncado — conteúdo original truncado]