Comment tracer 20 ans de données quotidiennes en séries chronologiques

9

J'ai le jeu de données suivant: https://dl.dropbox.com/u/22681355/ORACLE.csv et je voudrais tracer les changements quotidiens dans «Ouvrir» par «Date», j'ai donc fait ce qui suit:

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

et j'obtiens ce qui suit:

entrez la description de l'image ici

Maintenant, ce n'est évidemment pas le plus beau tracé jamais, alors je me demande quelle est la bonne méthode à utiliser pour tracer des données aussi détaillées?

dbr
la source
1
L'intrigue n'est pas si mauvaise ... mais comment l'améliorer dépend de ce que vous voulez souligner. Voulez-vous simplement tracer des données hebdomadaires? Voulez-vous ajouter une ligne lisse? Vous devez changer les étiquettes de l'axe des x, certainement ....
Peter Flom
Oui, je voudrais avoir des lignes lisses, comme ceci par exemple: dl.dropbox.com/u/22681355/Untitled.tiff , c'est ok si l'échelle est en années, mais la ligne lisse serait essentielle. J'ai essayé de changer le type en "l" mais cela n'a vraiment rien fait.
dbr
D' Rune manière d'ajouter des lignes douces est loess. Je suis sur le point de sortir, mais essayez? Loess dans R et, si vous avez des problèmes, modifiez votre message et quelqu'un pourra certainement vous aider. Il existe également d'autres méthodes de lissage, mais je pense que le loess est un bon défaut.
Peter Flom

Réponses:

8

Le problème avec vos données n'est pas qu'elles sont extrêmement détaillées: vous n'avez pas de valeurs le week-end, c'est pourquoi elles sont tracées avec des lacunes. Il y a deux façons de le gérer:

  1. Soit essayer de deviner les valeurs approximatives en fin de semaine avec des méthodes de lissage ( smooth.spline, loess, etc.). Le code d'interpolation simple est ci-dessous. Mais dans ce cas, vous introduirez quelque chose de "non naturel" et artificiel dans les données. C'est pourquoi je préfère la deuxième option.
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. Vous pouvez passer d'une base quotidienne à une base hebdomadaire, en faisant simplement la moyenne (par exemple) de cinq points séquentiels qui appartiennent à une semaine (dans ce cas, vous "tuez" certaines informations). Un petit exemple de la façon de procéder serait
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")

J'espère que cela vous aidera.

Dmitry Laptev
la source
1
merci, c'est vraiment utile. le problème est que, puisqu'il s'agit de données sur les stocks, le passage d'une base quotidienne à une base hebdomadaire pourrait certainement «tuer» certaines données cruciales. Existe-t-il un moyen d'avoir des lignes fluides pour les jours et des espaces vides pour les week-ends?
dbr
Ok, s'il est important pour vous de ne pas faire de moyenne, j'ai mis à jour la réponse, en fournissant l'exemple de code d'interpolation les week-ends.
Dmitry Laptev
@dbr Au fait, si vous voulez vous fier à R en interpolation, ce serait extrêmement simple:plot(as.Date(oracle$Date), oracle$Open, type='l')
Dmitry Laptev
1
Et au cas où vous voudriez simplement des écarts le week-end, remplacez la ligne openValues <- c(openValues, mean(oracle$Open[i:i-1]))de la première méthode paropenValues <- c(openValues, NA)
Dmitry Laptev
9

Étant donné que le problème est commun à de nombreux environnements logiciels statistiques, discutons-en ici sur Cross Validated plutôt que de le migrer vers un forum spécifique à R (tel que StackOverflow).

Le vrai problème est qu'il Dateest traité comme un facteur - une variable discrète - et que les lignes ne sont donc pas connectées correctement. (Les points ne sont pas non plus tracés parfaitement avec précision dans le sens horizontal.)

Comparaison de tracé

Pour faire le tracé de droite, le Datechamp a été converti d'un facteur en une date réelle, chaque semaine a été identifiée avec un calcul simple (en répartissant les semaines entre le samedi et le dimanche) et les lignes ont été interrompues le week-end en bouclant au fil des semaines:

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

(Une date équivalente à chaque semaine, donnant le lundi de cette semaine, a également été stockée dans la oracletrame de données car elle peut être utile pour tracer des données agrégées hebdomadaires.)

L'intention initiale peut être réalisée simplement en émulant la dernière ligne pour afficher toutes les données. Pour ajouter des informations sur le comportement saisonnier, le graphique suivant fait varier la couleur par semaine tout au long de chaque année civile:

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

Parcelle finale

whuber
la source
Pas un homme des finances, mais j'aime le truc des tendances saisonnières.
John Robertson
@John À l'origine, la couleur a été ajoutée juste pour aider l'œil. Mais après avoir regardé le résultat, je trouve intéressant que dans cinq des six années précédant l'explosion des actions Internet en 2000, les semaines oranges (à peu près à la fin de l'été) aient toutes affiché de fortes tendances à la hausse. Par la suite, cette tendance semble avoir disparu.
whuber
Je le remarque aussi et je me demande quelle est la relation, le cas échéant.
John Robertson
whuber et @John Robertson - Peut-être pas trop étroitement liés, mais 1998 a également été lorsque Microsoft est passé à leur base de code moderne avec Sql Server 7.0 / Sql Server 2000 et en 2000, ils fournissaient une concurrence plus forte à Oracle: en.wikipedia.org/wiki/ Microsoft_SQL_Server # Genesis
Rob
1
@Andre j'écrirais "Date". S'il s'agit de dates relatives, alors - si l'espace le permet - j'écrirais quelque chose comme «Années depuis le 1er janvier 1990». Dans cet exemple, j'espère qu'il est clair que seules les "années" plurielles suffiront. BTW, généralement j'analyse les données temporelles en utilisant des dates relatives (pour la stabilité numérique, la facilité de lecture des résumés statistiques, etc.) mais je les reconvertis en dates réelles pour les affichages graphiques (car les écrans doivent utiliser des unités de mesure significatives et interprétables) .
whuber
1

Je n'interpolerais pas le week-end. Très peu de bourses se négocient le samedi et aucune à ma connaissance le dimanche. Vous introduisez une estimation pour les données qui n'ont jamais existé, alors pourquoi ne pas simplement supprimer samedi et dimanche de l'ensemble de données? Je ferais quelque chose comme ci-dessous:

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)
SlowLearner
la source
oui, c'est ce que j'aimerais obtenir. mais n'y a-t-il pas un moyen plus simple de simplement laisser des espaces vides entre les lignes en le faisant «sauter» le week-end?
dbr
Je pense que R suppose que s'il y a des dates, elles doivent être utilisées, vous devez donc supprimer celles que vous ne voulez pas. Après tout, ce n'est pas difficile, le code ci-dessus est surtout superflu, le bit important est la suppression et cela ne nécessite qu'une seule ligne, c'est-à-dire mydf <- mydf [! (En semaine (as.Date (mydf $ mydate))% en% c ('Samedi', 'Dimanche')),]
SlowLearner
mais il est déjà supprimé dans le jeu de données, les dates de samedi et dimanche ne sont pas incluses
dbr
Ah. J'ai peut-être complètement mal compris votre question. Si vous voulez simplement lisser les données, je suis d'accord, quelque chose comme le loess est la voie à suivre, mais cela changera les données. Ou, vous pouvez créer une très, très grande image de l'intrigue qui montre les détails. 20 000 pixels de large ou quelque chose, par exemple.
SlowLearner
et que diriez-vous d'utiliser la solution de Dmitry mais au lieu d'imputer la moyenne de la valeur précédente et suivante imputant simplement 0?
dbr
0

En ce qui concerne l'apparence de votre intrigue, je suppose que l'ajout de plusieurs étiquettes sous l'axe x l'améliorerait visuellement. L'aspect de l'intrigue suggérée, vous pouvez voir ici http://imgur.com/ZTNPniA

Je ne sais pas comment faire une telle intrigue, c'est juste une idée (que je n'ai pas vue réalisée en R)

Robin des Bois
la source