9 votos

Cómo representar 20 años de datos diarios en series temporales

Tengo el siguiente conjunto de datos: https://dl.dropbox.com/u/22681355/ORACLE.csv y me gustaría trazar los cambios diarios en 'Open' por 'Date', así que hice lo siguiente:

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

y me sale lo siguiente:

enter image description here

Obviamente, este no es el mejor gráfico de la historia, así que me pregunto cuál es el método correcto para trazar datos tan detallados.

9voto

jldugger Puntos 7490

Dado que el problema es común a muchos entornos de software estadístico, vamos a discutirlo aquí en Validación cruzada en lugar de migrarlo a un foro específico de R (como StackOverflow).

El real cuestión es que Date se trata como un factor --una variable discreta-- y por eso las líneas no se están conectando correctamente. (Tampoco los puntos se trazan con perfecta precisión en la dirección horizontal).

Plot comparison

Para realizar el gráfico de la derecha, el Date El campo se convirtió de un factor a una fecha real, cada semana se identificó con un simple cálculo (rompiendo las semanas entre sábado y domingo) y las líneas se interrumpieron durante los fines de semana haciendo un bucle sobre las 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))

(Un equivalente a la fecha de cada semana, dando el lunes de esa semana, también se almacenó en el oracle dataframe porque puede ser útil para trazar datos agregados semanales).

La intención original se puede lograr simplemente emulando la última línea para mostrar todos los datos. Para añadir algo de información sobre el comportamiento estacional, el siguiente gráfico varía el color por semanas a lo largo de cada año natural:

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]))

Final plot

8voto

Dmitry Laptev Puntos 1846

El problema de tus datos no es que sean extremadamente detallados: no tienes valores en los fines de semana, por eso están trazados con huecos. Hay dos formas de solucionarlo:

  1. O bien intenta adivinar los valores aproximados en los fines de semana con algunos métodos de suavización ( smooth.spline , loess etc.). El código de la interpolación simple está abajo. Pero en este caso se introducirá algo "antinatural" y artificial a los datos. Por eso prefiero la segunda opción.
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. Se puede pasar de una base diaria a una base semanal, simplemente promediando (por ejemplo) cinco puntos secuenciales que corresponden a una semana (en este caso se está "matando" alguna información). Un ejemplo rápido de cómo hacerlo sería
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 sea de ayuda.

1voto

WinkyWolly Puntos 373

Yo no interpolaría los fines de semana. Muy pocas bolsas cotizan el sábado y ninguna, que yo sepa, el domingo. Estás introduciendo una estimación para unos datos que nunca han existido, así que ¿por qué no eliminar el sábado y el domingo del conjunto de datos? Yo haría algo como lo siguiente:

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)

0voto

fav Puntos 11

En cuanto al aspecto de tu gráfico, supongo que la adición de múltiples etiquetas bajo el eje x lo mejoraría visualmente. El aspecto del gráfico sugerido se puede ver aquí http://imgur.com/ZTNPniA

No sé cómo hacer esa trama, es sólo una idea (que no he visto realizada en R)

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X