Suavizar uma série temporal circular / periódica

9

Eu tenho dados para falhas de veículos a motor por hora do dia. Como seria de esperar, eles são altos no meio do dia e atingem o pico na hora do rush. O padrão geom_density do ggplot2 suaviza muito bem

Um subconjunto dos dados, para falhas relacionadas ao consumo de bebida, é alto no final do dia (noites e madrugadas) e mais alto nos extremos. Mas a geom_density padrão do ggplot2 ainda mergulha no extremo direito.

O que fazer em relação a isto? O objetivo é apenas a visualização - não há necessidade (existe?) De análise estatística robusta.

Imgur

x <- structure(list(hour = c(14, 1, 1, 9, 2, 11, 20, 5, 22, 13, 21, 
                        2, 22, 10, 18, 0, 2, 1, 2, 15, 20, 23, 17, 3, 3, 16, 19, 23, 
                        3, 4, 4, 22, 2, 21, 20, 1, 19, 18, 17, 23, 23, 3, 11, 4, 23, 
                        4, 7, 2, 3, 19, 2, 18, 3, 17, 1, 9, 19, 23, 9, 6, 2, 1, 23, 21, 
                        22, 22, 22, 20, 1, 21, 6, 2, 22, 23, 19, 17, 19, 3, 22, 21, 4, 
                        10, 17, 23, 3, 7, 19, 16, 2, 23, 4, 5, 1, 20, 7, 21, 19, 2, 21)
               , count = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
                           1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
                           1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
                           1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
                           1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
                           1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
                           1L, 1L, 1L, 1L, 1L, 1L, 1L))
          , .Names = c("hour", "count")
          , row.names = c(8L, 9L, 10L, 29L, 33L, 48L, 51L, 55L, 69L, 72L, 97L, 108L, 113L, 
                          118L, 126L, 140L, 150L, 171L, 177L, 184L, 202L, 230L, 236L, 240L, 
                          242L, 261L, 262L, 280L, 284L, 286L, 287L, 301L, 318L, 322L, 372L, 
                          380L, 385L, 432L, 448L, 462L, 463L, 495L, 539L, 557L, 563L, 566L, 
                          570L, 577L, 599L, 605L, 609L, 615L, 617L, 624L, 663L, 673L, 679L, 
                          682L, 707L, 730L, 733L, 746L, 754L, 757L, 762L, 781L, 793L, 815L, 
                          817L, 823L, 826L, 856L, 864L, 869L, 877L, 895L, 899L, 918L, 929L, 
                          937L, 962L, 963L, 978L, 980L, 981L, 995L, 1004L, 1005L, 1007L, 
                          1008L, 1012L, 1015L, 1020L, 1027L, 1055L, 1060L, 1078L, 1079L, 
                          1084L)
          , class = "data.frame")

ggplot(x, aes(hour)) + 
  geom_bar(binwidth = 1, position = "dodge", fill = "grey") +
  geom_density() + 
  aes(y = ..count..) +
  scale_x_continuous(breaks = seq(0,24,4))

Feliz por qualquer pessoa com melhor vocabulário de estatísticas editar esta pergunta, especialmente o título e as tags.

nacnudus
fonte

Respostas:

6

Para suavizar periodicamente (em qualquer plataforma), basta anexar os dados a si mesmos, suavizar a lista mais longa e cortar as extremidades.

Aqui está uma Rilustração:

y <- sqrt(table(factor(x[,"hour"], levels=0:23)))
y <- c(y,y,y)
x.mid <- 1:24; offset <- 24
plot(x.mid-1, y[x.mid+offset]^2, pch=19, xlab="Hour", ylab="Count")
y.smooth <- lowess(y, f=1/8)
lines(x.mid-1, y.smooth$y[x.mid+offset]^2, lwd=2, col="Blue")

(Como essas são contagens, escolhi suavizar suas raízes quadradas; elas foram convertidas novamente em contagens para plotagem.) A extensão lowessfoi reduzida consideravelmente em relação ao padrão, f=2/3porque (a) agora estamos processando uma matriz três vezes mais, o que deve nos faz reduzir para ; e (b) eu quero uma suavidade local razoavelmente, para que nenhum efeito apreciável do ponto final apareça no terço médio.2 / 9f2/9

Ele fez um bom trabalho com esses dados. Em particular, a anomalia na hora 0 foi suavizada.

Enredo

whuber
fonte
Isso responde à minha necessidade de uma visualização simples, mas por desinteresse, é um pouco de clamor? Usar algo do link de Nick evitaria efeitos de ponto final?
Nacnudus
1
Isso é exatamente equivalente ao método que eu usei, desde que a largura da janela seja escolhida com cuidado, como o @whuber fez. Mas o software R está prontamente disponível para fazer o que eu fiz. (I foi originalmente delegando a tarefa de encontrá-lo com especialistas R, mas não percebeu.)
Nick Cox
3
Não vejo isso como um kluge: essa técnica é baseada na definição de periodicidade. Funciona para qualquer local suave. (Ele não funcionará para um bom nível global, mas isso não é um problema, porque a maioria dos smoothers globais é derivada de métodos inerentemente periódicos, como a série Fourier). com meia largura máxima , é necessário alinhar apenas os últimos valores de da sequência no início e o primeiro no final, mas não há mal nenhum em expandir a sequência de maneira conservadora - é apenas menos eficiente . k - 1 k - 1kk-1k-1
whuber
1
@whuber Bastante. Eu estava apenas aludindo ao truísmo de que o que você adiciona como cópias antes e depois dos dados reais deve ser consistente com o quanto você suaviza.
Nick Cox
7

Eu não uso R rotineiramente e nunca usei ggplot, mas há uma história simples aqui, ou pelo menos acho.

A hora do dia é manifestamente uma variável circular ou periódica. Nos seus dados, você tem as horas 0 (1) 23 que são agrupadas, de modo que 23 é seguido por 0. No entanto, você ggplotnão sabe disso, pelo menos com as informações que você forneceu. No que diz respeito a ele, pode haver valores em -1, -2, etc. ou em 24, 25, etc. os dados possíveis.

Isso também estará acontecendo nos seus dados principais, mas não é tão perceptível.

Se você deseja estimativas de densidade de kernel para esses dados, precisa de uma rotina inteligente o suficiente para lidar com essas variáveis ​​periódicas ou circulares corretamente. "Corretamente" significa que a rotina suaviza um espaço circular, reconhecendo que 0 segue 23. De certa forma, a suavização dessas distribuições é mais fácil do que o caso usual, pois não há problemas de limite (como não há limites). Outros devem poder aconselhar sobre as funções a serem usadas em R.

Esse tipo de dado se situa entre séries temporais periódicas e estatísticas circulares.

Os dados apresentados possuem 99 observações. Por isso, um histograma funciona muito bem, embora eu possa ver que você pode querer suavizá-lo um pouco.

insira a descrição da imagem aqui

(ATUALIZAÇÃO) É uma questão de gosto e julgamento, mas eu consideraria sua curva suave drasticamente exagerada.

Aqui, como amostra, está uma estimativa de densidade bi-ponderada. Eu usei meu próprio programa Stata para dados circulares em graus com a conversão ad hoc 15 * (hora + 0,5), mas densidades expressas por hora. Isso, por outro lado, é um pouco fraco, mas você pode ajustar suas escolhas.

insira a descrição da imagem aqui

Nick Cox
fonte
1
Concordo que está super liso, mas é o princípio que estou abordando. Alguma pesquisa no seu vocabulário útil (circular, periódica) revela surpreendentemente pouco interesse nesse tipo de problema, mas esperarei um pouco mais para que alguém se comunique com os conselhos de R.
Nacnudus
5

Ao executar 4253H de Tukey, duas vezes em três cópias concatenadas, as contagens brutas e, em seguida, obter o conjunto intermediário de valores suavizados, dá a mesma imagem da baixada do whuber nas raízes quadradas das contagens.
insira a descrição da imagem aqui

Ray Koopman
fonte
2
+1 Prefiro as esposas de Tukey e fico feliz em ver um exemplo de uma delas aqui.
whuber
1
Esta receita precisa foi elaborada por Paul F. Velleman, mas sem dúvida sob a orientação de Tukey. O "42" reduz os artefatos da escada.
Nick Cox
2

Além disso, e como uma alternativa mais complexa, ao que foi sugerido, convém procurar splines periódicos. Você pode encontrar ferramentas para ajustá-las nos pacotes R splinese no mgcv. A vantagem que vejo sobre as abordagens já sugeridas é que você pode calcular graus de liberdade de adaptação, o que não é óbvio no método das três cópias.

F. Tusell
fonte
1
(+1) Alguns comentários: Primeiro, "três cópias" é um aplicativo específico, não uma regra geral. Segundo, acredito que o cálculo do DF é igualmente simples: a quantidade de dados permanece a mesma e subtrai o número de parâmetros usados ​​no ajuste do spline.
whuber
@ whuber: não está claro para mim como fazer o último bit (como calcular os parâmetros usados ​​para ajustar o spline se você o ajustar nas "três cópias").
F. Tusell
1
A parte de cópia não altera a quantidade de dados, portanto, o que importa na estimativa do DF é contar os parâmetros usados ​​pelos splines.
whuber
1

Ainda outra abordagem, splines periódicas (como sugerido na resposta de F.Tusell), mas aqui também mostramos uma implementação em R. Usaremos um Poisson glm para ajustar as contagens do histograma, resultando no seguinte histograma com suavidade:

insira a descrição da imagem aqui

O código usado (começando com o objeto de dados xfornecido em questão):

library(pbs) # basis for periodic spline

x.tab <- with(x, table(factor(hour,levels=as.character(0:23))))
x.df <- data.frame(time=0:23, count=as.vector(x.tab))
mod.hist <- with(x.df, glm(count ~ pbs::pbs(time, df=4, Boundary.knots=c(0,24)), family=poisson))
pred <- predict(mod.hist, type="response", newdata=data.frame(time=0:24))

with(x.df, {plot(time, count,type="h",col="blue", main="Histogram") ; lines(time, pred[1:24], col="red")} )
kjetil b halvorsen
fonte