Como plotar 20 anos de dados diários em séries temporais

9

Eu tenho o seguinte conjunto de dados: https://dl.dropbox.com/u/22681355/ORACLE.csv e gostaria de plotar as alterações diárias em 'Abrir' por 'Data', então fiz o seguinte:

oracle <- read.csv(file="http://dl.dropbox.com/u/22681355/ORACLE.csv", header=TRUE)
plot(oracle$Date, oracle$Open, type="l")

e recebo o seguinte:

insira a descrição da imagem aqui

Agora, obviamente, este não é o melhor enredo de todos os tempos, então estou me perguntando qual é o método certo a ser usado ao plotar dados tão detalhados?

dbr
fonte
11
O enredo não é tão ruim ... mas como melhorá-lo depende do que você deseja enfatizar. Deseja apenas plotar dados semanais? Deseja adicionar uma linha suave? Você deve alterar os rótulos do eixo x, certamente ....
Peter Flom - Reintegrar Monica
Sim, eu gostaria de ter linhas suaves, como esta, por exemplo: dl.dropbox.com/u/22681355/Untitled.tiff , tudo bem se a escala for em anos, mas a linha suave seria essencial. Eu tentei mudar o tipo para "l", mas realmente não fez nada.
DBR
De Ruma maneira de adicionar linhas suaves é loess. Estou saindo, mas tente sair do R e, se tiver problemas, edite sua postagem e alguém certamente poderá ajudá-lo. Também existem outros métodos de suavização, mas acho que loess é um bom padrão.
Peter Flom - Restabelece Monica

Respostas:

8

O problema com seus dados não é que eles sejam extremamente detalhados: você não tem valores nos finais de semana, é por isso que é plotado com lacunas. Existem duas maneiras de lidar com isso:

  1. Ou tentar adivinhar valores aproximados em fins de semana com alguns métodos de alisamento ( smooth.spline, loess, etc.). O código de interpolação simples está abaixo. Mas, neste caso, você apresentará algo "não natural" e artificial aos dados. Por isso prefiro a segunda opção.
currentDate <- min(as.Date(oracle$Date))
dates <- c(currentDate)
openValues <- c(oracle$Open[5045])
i <- 5044
while (i > 0) {
  currentDate <- currentDate + 1;
  dates <- c(dates, currentDate)
  if (currentDate == as.Date(oracle$Date[i])) {
        # just copy value and move
        openValues <- c(openValues, oracle$Open[i])
        i <- i-1
      } else {
        # interpolate value
        openValues <- c(openValues, mean(oracle$Open[i:i-1]))
  }
}
plot(dates, openValues, type="l")
  1. Você pode ir de uma base diária para uma semanal, calculando a média (por exemplo) de cinco pontos seqüenciais que chegam a uma semana (nesse caso, você está "matando" algumas informações). Apenas um exemplo rápido de como fazer isso seria
openValues = c(mean(oracle$Open[1:5]));
dates = c(as.Date(oracle$Date[1]));
for (i in seq(6,5045,5)) {
  openValues = c(openValues, mean(oracle$Open[i:i+5]));
      dates = c(dates, as.Date(oracle$Date[i]));
}
plot(dates, openValues, type="l")

Espero que ajude.

Dmitry Laptev
fonte
11
obrigado, isso é realmente útil. o problema é que, como se trata de dados de estoque, mudar diariamente para semanalmente pode definitivamente 'matar' alguns dados cruciais. Existe alguma maneira de ter linhas suaves para os dias e espaços vazios nos finais de semana?
DBR
Ok, se é importante que você não calcule a média, atualizei a resposta, fornecendo o código de exemplo para interpolar os fins de semana.
Dmitry Laptev
@dbr By the way, se você quer contar com R na interpolação, que seria extremamente fácil:plot(as.Date(oracle$Date), oracle$Open, type='l')
Dmitry Laptev
11
E no caso de você simplesmente quer lacunas quando fins de semana, substitua a linha openValues <- c(openValues, mean(oracle$Open[i:i-1]))no primeiro método comopenValues <- c(openValues, NA)
Dmitry Laptev
9

Como o problema é comum a muitos ambientes de software estatístico, vamos discuti-lo aqui em Validação cruzada, em vez de migrá-lo para um fórum específico de R (como StackOverflow).

A questão real é que isso Dateé tratado como um fator - uma variável discreta - e, portanto, as linhas não estão sendo conectadas corretamente. (Os pontos também não são plotados perfeitamente com precisão na direção horizontal.)

Comparação de parcelas

Para fazer o gráfico à direita, o Datecampo foi convertido de um fator para uma data real, cada semana foi identificada com um cálculo simples (quebrando as semanas entre sábado e domingo) e as linhas foram interrompidas nos finais de semana, fazendo um loop ao longo das semanas:

oracle$date <- as.Date(oracle$Date)
oracle$week.num <- (as.integer(oracle$date) + 3) %/% 7 
oracle$week <- as.Date(oracle$week.num * 7 - 3, as.Date("1970-01-01", "%Y-%m-%d"))

par(mfrow=c(1,2))
plot(as.factor(unclass(oracle$Date[1:120])), oracle$Open[1:120], type="l",
     main="Original Plot: Inset", xlab="Factor code")
plot(oracle$date[1:120], oracle$Open[1:120], type="n", ylab="Price", 
     main="Oracle Opening Prices")
tmp <- by(oracle[1:120,], oracle$week[1:120], function(x) lines(x$date, x$Open, lwd=2))

(Uma data equivalente a cada semana, fornecendo a segunda-feira dessa semana, também foi armazenada no oracledataframe porque pode ser útil para plotar dados agregados semanais.)

A intenção original pode ser alcançada simplesmente emulando a última linha para exibir todos os dados. Para adicionar algumas informações sobre o comportamento sazonal, a seguinte plotagem varia de cor por semana ao longo de cada ano civil:

par(mfrow=c(1,1))
colors <- terrain.colors(52)
plot(oracle$date, oracle$Open, type="n", main="Oracle Opening Prices")
tmp <- by(oracle, oracle$week, 
          function(x) lines(x$date, x$Open, col=colors[x$week.num %% 52 + 1]))

Trama final

whuber
fonte
Não sou uma pessoa financeira, mas gosto do truque das tendências sazonais.
John Robertson
@ John Originalmente, a cor foi adicionada apenas para ajudar os olhos. Mas, olhando para o resultado, acho interessante que, nos cinco anos anteriores à explosão da Internet em 2000, as semanas laranja (aproximadamente no final do verão) exibiram fortes tendências ascendentes. Depois, essa tendência parece ter desaparecido.
whuber
Percebo isso também e me perguntei qual seria o relacionamento.
31712 John Robertson
whuber e @John Robertson - Pode não estar muito relacionado, mas 1998 foi também quando a Microsoft mudou para sua moderna base de código com o Sql Server 7.0 / Sql Server 2000 e, em 2000, eles estavam oferecendo uma concorrência mais forte ao Oracle: en.wikipedia.org/wiki/ Microsoft_SQL_Server # Genesis
Rob
11
@ André eu escreveria "Data". Se forem datas relativas, então - se o espaço permitir - eu escreveria algo como "Anos desde 1º de janeiro de 1990". Nesse exemplo, espero que fique claro que apenas o "ano" plural será suficiente. BTW, normalmente analisarei dados relacionados ao tempo usando datas relativas (para estabilidade numérica, facilidade de leitura de resumos estatísticos etc.), mas os converteremos novamente em datas reais para exibições gráficas (porque as exibições devem usar unidades de medida significativas e interpretáveis) .
whuber
1

Eu não interpolava nos fins de semana. Poucas bolsas são negociadas no sábado e nenhuma que eu saiba no domingo. Você está introduzindo uma estimativa para os dados que nunca existiram. Por que não remover sábado e domingo do conjunto de dados? Eu faria algo como o abaixo:

require(ggplot2)
require(scales)
require(gridExtra)
require(lubridate)
require(reshape)

set.seed(12345)

# Create data frame from random data
daysback <- 1000 # number of days, only a few for this example
startdate <- as.Date(format(now()), format = "%Y-%m-%d") - days(daysback)
mydf <- data.frame(mydate = seq(as.Date(startdate), by = "day", length.out = daysback),
                   open = runif(daysback, min = 600, max = 800))

# Now that we have a data frame, remove the weekend days
mydf <- mydf[!(weekdays(as.Date(mydf$mydate)) %in% c('Saturday','Sunday')),] # remove weekend days
    # Calculate change, except for the first date
    mydf$diff <- c(NA, diff(mydf$open))
    # Remove first row with no 'diff' value
    firstdate <- head(mydf$mydate, 1)
mydf <- mydf[mydf$mydate > firstdate, ]

p <- ggplot(mydf, aes(x = mydate, y = diff)) +
    geom_bar(data = mydf, stat = "identity", fill = "red")

print(p)
Aprendiz lento
fonte
sim, é isso que eu gostaria de receber. mas não há uma maneira mais fácil, basta deixar espaços vazios entre as linhas, fazendo com que ele pule os fins de semana?
DBR
Eu acho que R pressupõe que, se houver datas, elas estão lá para serem usadas, então você deve remover aquelas que não deseja. Afinal, não é difícil, o código acima é em grande parte supérfluo, o importante é a remoção e isso requer apenas uma linha, por exemplo, mydf <- mydf [! (Dias da semana (as.Date (mydf $ mydate))% em% c ('Saturday', 'Sunday'))]]
SlowLearner
mas já foi removido no conjunto de dados, as datas para sábado e domingo não estão incluídas
dbr
Ah Eu posso ter entendido completamente sua pergunta. Se você apenas deseja suavizar os dados, concordo, algo como loess é o caminho a seguir, mas isso mudará os dados. Ou você pode criar uma imagem muito, muito grande do gráfico que mostra os detalhes. 20.000 pixels de largura ou algo assim, por exemplo.
SlowLearner
e que tal usar a solução de Dmitry, mas em vez de imputar a média do valor anterior e seguinte, apenas imputando zero?
DBR
0

Em relação à aparência do seu gráfico, suponho que a adição de vários rótulos no eixo x o melhoraria visualmente. A aparência do gráfico sugerido você pode ver aqui http://imgur.com/ZTNPniA

Eu não sei como fazer esse enredo, é apenas uma ideia (que eu não vi realizada em R)

Robin Hood
fonte