Cómo trazar 20 años de datos diarios en series de tiempo

9

Tengo el siguiente conjunto de datos: https://dl.dropbox.com/u/22681355/ORACLE.csv y me gustaría trazar los cambios diarios en 'Abrir' por 'Fecha', 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:

ingrese la descripción de la imagen aquí

Obviamente, esta no es la mejor trama, así que me pregunto cuál es el método correcto para trazar datos tan detallados.

dbr
fuente
1
La trama en realidad no es tan mala ... pero cómo mejorarla depende de lo que quieras enfatizar. ¿Desea simplemente trazar datos semanales? ¿Quieres agregar una línea suave? Debería cambiar las etiquetas del eje x, ciertamente ...
Peter Flom - Restablecer Monica
Sí, me gustaría tener líneas suaves, como esta por ejemplo: dl.dropbox.com/u/22681355/Untitled.tiff , está bien si la escala es en años, pero la línea suave sería esencial. Intenté cambiar el tipo a "l" pero realmente no hizo nada.
dbr
En Runa forma de agregar líneas suaves es loess. Estoy saliendo, pero intente loess en R y, si tiene problemas, edite su publicación y ciertamente alguien podrá ayudarlo. También hay otros métodos de suavizado, pero creo que loess es un buen valor predeterminado.
Peter Flom - Restablece a Monica

Respuestas:

8

El problema con sus datos no es que sean extremadamente detallados: no tiene valores los fines de semana, es por eso que se trazan con huecos. Hay dos formas de lidiar con esto:

  1. Cualquiera de tratar de adivinar valores aproximados en los fines de semana con algunos métodos de suavizado ( smooth.spline, loess, etc.). El código de interpolación simple está abajo. Pero en este caso, introducirá algo "antinatural" y artificial en 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. Puede pasar de una base diaria a una semanal, simplemente promediando (por ejemplo) cinco puntos secuenciales que corresponden a una semana (en este caso está "matando" alguna información). Solo 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 ayude.

Dmitry Laptev
fuente
1
Gracias, esto es realmente útil. El problema es que, dado que se trata de datos de existencias, pasar de una base diaria a otra podría definitivamente "matar" algunos datos cruciales. ¿Hay alguna forma de tener líneas suaves para los días y espacios vacíos para los fines de semana?
dbr
Ok, si es importante que no promedies, he actualizado la respuesta, proporcionando el código de muestra para interpolar los fines de semana.
Dmitry Laptev
@dbr Por cierto, si quieres confiar en R en la interpolación, eso sería extremadamente fácil:plot(as.Date(oracle$Date), oracle$Open, type='l')
Dmitry Laptev
1
Y en caso de que simplemente desee brechas los fines de semana, reemplace la línea openValues <- c(openValues, mean(oracle$Open[i:i-1]))en el primer método conopenValues <- c(openValues, NA)
Dmitry Laptev
9

Debido a que el problema es común en muchos entornos de software estadístico, analicémoslo aquí en Cross Validated en lugar de migrarlo a un foro específico de R (como StackOverflow).

El problema real es que Datese trata como un factor, una variable discreta, por lo que las líneas no se conectan correctamente. (Tampoco los puntos se trazan con precisión perfecta en la dirección horizontal).

Comparación de trama

Para hacer el diagrama a la derecha, el Datecampo se convirtió de un factor a una fecha real, cada semana se identificó con un cálculo simple (rompiendo las semanas entre el sábado y el domingo) y las líneas se interrumpieron durante los fines de semana al recorrer 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))

(Una fecha equivalente de cada semana, que da el lunes de esa semana, también se almacenó en el oraclemarco de datos 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 agregar información sobre el comportamiento estacional, la siguiente gráfica varía el color por semana durante cada año calendario:

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
fuente
No soy una persona de finanzas, pero me gusta el truco de tendencias estacionales.
John Robertson
@John Originalmente, el color se agregó solo para ayudar a la vista. Pero después de mirar el resultado, me parece interesante que en cinco de los seis años anteriores a la explosión de las existencias de Internet en 2000, las semanas naranjas (aproximadamente a fines del verano) exhibieron fuertes tendencias al alza. Luego, esa tendencia parece haberse desvanecido.
whuber
También me di cuenta y me pregunté cuál era la relación, si la hubiera.
John Robertson
whuber y @John Robertson - Puede que no estén demasiado relacionados, pero 1998 también fue cuando Microsoft se mudó a su moderna base de código con Sql Server 7.0 / Sql Server 2000 y para el año 2000 estaban proporcionando una competencia más fuerte a Oracle: en.wikipedia.org/wiki/ Microsoft_SQL_Server # Genesis
Rob
1
@ Andre escribiría "Fecha". Si se trata de fechas relativas, entonces, si el espacio lo permite, escribiría algo así como "Años desde el 1 de enero de 1990". En ese ejemplo, espero que quede claro que solo los "años" plurales funcionarán. Por cierto, generalmente analizaré datos relacionados con el tiempo usando fechas relativas (para estabilidad numérica, facilidad para leer resúmenes estadísticos, etc.) pero los convertiré nuevamente en fechas reales para pantallas gráficas (porque las pantallas deben usar unidades de medida significativas e interpretables) .
whuber
1

No interpolaría los fines de semana. Muy pocas bolsas de valores cotizan el sábado y ninguna que yo sepa el domingo. Está introduciendo una estimación de datos que nunca existieron, así que ¿por qué no simplemente eliminar el sábado y el domingo del conjunto de datos? 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)
Aprendiz lento
fuente
Sí, esto es lo que me gustaría obtener. pero ¿no hay una manera más fácil simplemente dejando espacios vacíos entre las líneas haciendo que se 'salteen' los fines de semana?
dbr
Creo que R asume que si hay fechas, están allí para ser utilizadas, por lo que debe eliminar las que no desee. Después de todo, no es difícil, el código anterior es en su mayoría superfluo, lo importante es la eliminación y eso solo requiere una línea, es decir, mydf <- mydf [! (Weekdays (as.Date (mydf $ mydate))% en% c ('Sábado', 'Domingo')),]
SlowLearner
pero ya se eliminó en el conjunto de datos, las fechas para el sábado y el domingo no están incluidas
dbr
Ah Puede que haya entendido mal tu pregunta. Si solo desea suavizar los datos, estoy de acuerdo, algo como loess es el camino a seguir, pero eso cambiará los datos. O bien, puede crear una imagen muy, muy grande de la trama que muestre los detalles. 20,000 píxeles de ancho o algo así, por ejemplo.
SlowLearner
¿Y qué hay de usar la solución de Dmitry pero en lugar de imputar la media del valor anterior y el siguiente simplemente imponer 0?
dbr
0

Con respecto al aspecto de su trama, supongo que la adición de múltiples etiquetas debajo del eje x lo mejoraría visualmente. El aspecto de la trama sugerida se puede ver aquí http://imgur.com/ZTNPniA

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

Robin Hood
fuente