Come tracciare 20 anni di dati giornalieri in serie temporali


9

Ho il seguente set di dati: https://dl.dropbox.com/u/22681355/ORACLE.csv e vorrei tracciare le modifiche giornaliere in "Apri" per "Data", quindi ho fatto quanto segue:

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

e ottengo il seguente:

inserisci qui la descrizione dell'immagine

Ora, ovviamente, questa non è la trama più bella di sempre, quindi mi chiedo quale sia il metodo giusto da utilizzare per la stampa di dati così dettagliati?


1
La trama in realtà non è poi così male .... ma come migliorarla dipende da cosa vuoi sottolineare. Vuoi tracciare solo dati settimanali? Vuoi aggiungere una linea liscia? Dovresti cambiare le etichette dell'asse x, certamente ....
Peter Flom

Sì, vorrei avere linee morbide, come ad esempio questa: dl.dropbox.com/u/22681355/Untitled.tiff , va bene se la scala è in anni, ma la linea liscia sarebbe essenziale. Ho provato a cambiare il tipo in "l" ma in realtà non ha fatto nulla.
dal

In Run modo è possibile aggiungere linee morbide loess. Sto uscendo, ma prova? Loess in R e, se hai problemi, modifica il tuo post e qualcuno sarà sicuramente in grado di aiutarti. Esistono anche altri metodi di smoothing, ma penso che il loess sia un buon default.
Peter Flom

Risposte:


8

Il problema con i tuoi dati non è che sono estremamente dettagliati: non hai valori nei fine settimana, ecco perché sono tracciati con lacune. Esistono due modi per gestirlo:

  1. O cercare di indovinare valori approssimativi in week-end con alcuni metodi di lisciatura ( smooth.spline, loess, ecc). Il codice di interpolazione semplice è di seguito. Ma in questo caso introducerai qualcosa di "innaturale" e artificiale nei dati. Ecco perché preferisco la seconda opzione.
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. Puoi passare da una base giornaliera a una base settimanale, calcolando in media (ad esempio) cinque punti sequenziali che arrivano a una settimana (in questo caso stai "uccidendo" alcune informazioni). Sarebbe solo un rapido esempio di come farlo
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")

Spero che possa aiutare.


1
grazie, è davvero utile. il problema è che dal momento che si tratta di dati di borsa, il passaggio dalla base giornaliera a quella settimanale potrebbe sicuramente "uccidere" alcuni dati cruciali. C'è un modo per avere linee morbide per i giorni e spazi vuoti per i fine settimana?
dal

Ok, se per te è importante non fare la media, allora ho aggiornato la risposta, fornendo il codice di esempio di interpolazione dei fine settimana.
Dmitry Laptev,

@dbr A proposito, se vuoi fare affidamento su R nell'interpolazione, sarebbe estremamente facile:plot(as.Date(oracle$Date), oracle$Open, type='l')
Dmitry Laptev,

1
E nel caso in cui si desideri semplicemente spazi vuoti durante i fine settimana, sostituire la riga openValues <- c(openValues, mean(oracle$Open[i:i-1]))nel primo metodo conopenValues <- c(openValues, NA)
Dmitry Laptev,

9

Poiché il problema è comune a molti ambienti software statistici, discutiamolo qui su Cross Validated anziché migrarlo in un forum specifico per R (come StackOverflow).

Il vero problema è che Dateviene trattato come un fattore - una variabile discreta - e quindi le linee non vengono collegate correttamente. (Né i punti vengono tracciati in modo perfettamente accurato in direzione orizzontale.)

Confronto della trama

Per creare il diagramma a destra, il Datecampo è stato convertito da un fattore a una data effettiva, ogni settimana è stata identificata con un semplice calcolo (interrompendo le settimane tra sabato e domenica) e le linee sono state interrotte nei fine settimana ripetendo ciclicamente le settimane:

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 data equivalente di ogni settimana, che oracleindica il lunedì di quella settimana, è stata anche memorizzata nel frame di dati perché può essere utile per tracciare dati aggregati settimanali.)

L'intenzione originale può essere raggiunta semplicemente emulando l'ultima riga per visualizzare tutti i dati. Per aggiungere alcune informazioni sul comportamento stagionale, la seguente trama varia il colore per settimana durante ogni anno solare:

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 finale


Non una persona finanziaria, ma mi piace il trucco di tendenza stagionale.
John Robertson,

@John Inizialmente il colore veniva aggiunto solo per aiutare la vista. Ma dopo aver visto il risultato, trovo interessante il fatto che in cinque dei sei anni precedenti lo scoppio delle scorte di Internet nel 2000, le settimane arancioni (all'incirca alla fine dell'estate) abbiano mostrato forti tendenze al rialzo. Successivamente, quella tendenza sembra essere svanita.
whuber

Lo noto anche io e mi chiedevo quale fosse la relazione.
John Robertson,

whuber e @John Robertson - Potrebbe non essere strettamente correlato ma il 1998 è stato anche quando Microsoft è passata alla loro base di codice moderna con Sql Server 7.0 / Sql Server 2000 e nel 2000 stavano fornendo una forte concorrenza a Oracle: en.wikipedia.org/wiki/ Microsoft_SQL_Server # Genesis
Rob

1
@Andre scriverei "Data". Se si tratta di date relative, quindi - spazio permettendo - scriverei qualcosa del tipo "Anni dal 1 ° gennaio 1990". In questo esempio spero sia chiaro che solo gli "anni" plurali lo faranno. A proposito, di solito analizzerò i dati relativi al tempo usando le date relative (per stabilità numerica, facilità di lettura dei riassunti statistici, ecc.) Ma li convertirò di nuovo in date effettive per i display grafici (perché i display dovrebbero usare unità di misura significative e interpretabili) .
whuber

1

Non interpolerei nei fine settimana. Pochissime borse vengono scambiate sabato e nessuna di quelle che conosco domenica. Stai introducendo una stima per i dati che non sono mai esistiti, quindi perché non rimuovere semplicemente sabato e domenica dal set di dati? Vorrei fare qualcosa come il seguente:

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)

sì, questo è quello che vorrei ottenere. ma non c'è un modo più semplice semplicemente lasciando degli spazi vuoti tra le linee facendolo saltare i fine settimana?
dal

Penso che R presuma che se ci sono date, sono lì per essere usate, quindi dovresti rimuovere quelle che non vuoi. Dopotutto, non è difficile, il codice sopra è per lo più superfluo, il bit importante è la rimozione e che richiede solo una riga, cioè mydf <- mydf [! (Giorni della settimana (as.Date (mydf $ mydate))% in% c ('Saturday', 'Sunday')),]
SlowLearner,

ma è già stato rimosso nel set di dati, le date per sabato e domenica non sono incluse
dbr

Ah. Potrei aver frainteso completamente la tua domanda. Se vuoi solo smussare i dati, sono d'accordo, qualcosa come loess è la strada da percorrere, ma questo cambierà i dati. Oppure puoi creare un'immagine molto, molto grande della trama che mostra i dettagli. 20.000 pixel di larghezza o qualcosa del genere, per esempio.
SlowLearner,

e che ne dici di usare la soluzione di Dmitry ma invece di imputare la media del valore precedente e successivo solo imputando gli 0?
dal

0

Per quanto riguarda l'aspetto della tua trama, suppongo che l'aggiunta di più etichette sotto l'asse x la migliorerebbe visivamente. L'aspetto della trama suggerita è disponibile qui http://imgur.com/ZTNPniA

Non so come realizzare una trama del genere, è solo un'idea (che non ho visto realizzato in R)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.