7.12 Identificação de eventos discretos

Frequentemente precisamos separar a série temporal de uma variável em eventos discretos, como a identificação de períodos extremos ou de risco, como secas, tempestades, ondas de calor, períodos de poluição atmosférica crítica (acima ou abaixo de um limiar de concentração do poluentes) e etc.

Para caracterização destes eventos as informação essencias são o início, o fim e a duração de cada evento. Com essas informações podemos identificar cada evento e extrair outros atributos, na escala de evento, para aprofundar a análise.

Para ilustrar a conveniência das funções vistas até agora, veremos uma forma geral para identificação de eventos. O evento de interesse será o período da estação chuvosa nos dados prec. Neste exemplo, a estação chuvosa é definida quando prec > 100 mm mês-1.

O primeiro passo é identificar a ocorrência dos eventos.

limiar <- 100
# definição de evento (condição)
(x <- evts <- as.integer(prec > limiar))
#>  [1] 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 1 0 1

A conversão dos eventos de lógico para numérico é opcional26 e foi usada apenas para facilitar a localização dos eventos visualmente (1: ocorrência de evento, 0: não ocorrência). A partir daí, o problema consiste em identificar sequências de elementos adjacentes iguais (sequências de 1 repetidos).

As posições iniciais de cada evento podem ser encontradas subtraindo o elemento prévio (lag(x)) do elemento atual (x). Se a diferença for -1 temos o início de um evento. A tabela abaixo permite visualizar melhor isso.

elemento 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
x 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 1 0 1
lag(x) NA 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 1 0
pos_ini NA 0 0 1 0 0 0 0 -1 0 0 0 0 0 0 1 0 0 0 0 0 -1 1 -1
# x atrasado: desloca os elementos para para frente
pos_ini <- which(lag(x) - x < 0)
# ajuste do primeiro elemento de pos_ini
pos_prim <- ifelse(
  test = x[1] == 1,
  yes = 1,
  no = 0
)
(pos_ini <- c(pos_prim, pos_ini))
#> [1]  1  9 22 24
# datas de início dos eventos
dts[pos_ini]
#> [1] "2010-01-01" "2010-09-01" "2011-10-01" "2011-12-01"

Temos que ter cuidado especial com o primeiro índice das posições iniciais (pos_prim), ajustando-o para considerar adequadamente eventos começando logo início do vetor. Esse ajuste é necessário porque usando a diferença do vetor defasado não há como detectar se o primeiro elemento é evento ou não.

Analogamente, as posições finais de cada evento podem ser encontradas subtraindo o elemento seguinte (lead(x)) do elemento atual (x). Quando essa diferença é -1 temos o fim de um evento, o que pode ser visualizado na tabela abaixo.

elemento 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
x 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 1 0 1
lead(x) 1 1 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 1 0 1 NA
pos_fim 0 0 -1 0 0 0 0 1 0 0 0 0 0 0 -1 0 0 0 0 0 1 -1 1 NA
pos_fim <- which(lead(x) - x < 0)
# ajuste do último elemento de pos_fim
pos_ult <- ifelse(
  test = x[length(x)] == 1,
  yes = length(x),
  no = 0
)
(pos_fim <- c(pos_fim, pos_ult))
#> [1]  3 15 22 24
# datas do fim dos eventos
dts[pos_fim]
#> [1] "2010-03-01" "2011-03-01" "2011-10-01" "2011-12-01"

O último índice do vetor de posições finais requer tratamento similar ao do 1° elemento das posições iniciais. Ele deve ser ajustado para tratar dos casos com eventos no último elemento de x.

A duração de cada evento é facilmente obtida do fim e início de cada evento:

duracao <- pos_fim - pos_ini + 1
duracao
#> [1] 3 7 1 1
# rbind(x, atras = lag(x), adiant = lead(x), pos_ini = lag(x)-x, pos_fim = lead(x) - x)

Eventualmente você pode precisar de um vetor identificando cada evento, o que pode ser feito usando:

evts_id <- evts
evts_id[evts > 0] <- rep(seq_along(duracao), times = duracao)
evts_id
#>  [1] 1 1 1 0 0 0 0 0 2 2 2 2 2 2 2 0 0 0 0 0 0 3 0 4

Este vetor pode ser usado, para obter estatísticas de cada evento. Por exemplo, a precipitação média em cada evento pode ser determinada passando este vetor como argumento da função tapply(). Como só queremos informação nos eventos vamos substituir os valores = 0 por NA em evts_id. Assim, a tapply() retornará a média só para os eventos de interesse.

evts_id <- ifelse(evts_id == 0, NA, evts_id)
# prec média em cada evento
tapply(
  X = prec,
  INDEX = evts_id,
  FUN = mean
)
#>        1        2        3        4 
#> 198.3333 193.5714 120.0000 208.0000

A tapply() tem três argumentos:

  • X: dados que queremos aplicar a função

  • INDEX: vetor de índices com os grupos para os quais a função será aplicada separadamente.

  • FUN: a função que desejamos aplicar aos dados (e.g.: mean(), ``)


  1. Isso significa que os resultados nos códigos abaixo não se alteram se removermos essa conversão.