2012-01-22 2 views
0

R: comment puis-je remplir les lignes d'une trame de données, dans laquelle chaque ligne représente un jour, avec une seule valeur commune pour chaque année?Comment puis-je remplir les lignes d'une trame de données R, dans laquelle chaque ligne représente un jour, avec une seule valeur commune pour chaque jour d'une année?

J'ai une trame de données constituée d'une colonne de date, d'une colonne de prix et de diverses autres colonnes dérivées de ces deux colonnes. L'une des colonnes calcule, pour chaque jour d'une année donnée, la variation en pourcentage du prix depuis le début de cette année (ceci est lié à une question antérieure).

Je veux ajouter une colonne qui contient, pour chaque jour d'une année donnée, la variation en pourcentage du prix pour l'ensemble de cette année. Donc, si le prix a augmenté de 10% entre le premier et le dernier jour de 2009, la colonne pour tous les jours de 2009 devrait contenir la valeur de 10% (ou 0,1). Si le prix a baissé de 2% entre le premier et le dernier jour de 2010, la colonne pour chaque jour de 2010 devrait contenir la valeur -0,02 et ainsi de suite.

Le code que j'ai à ce jour est:

require(lubridate) 
require(plyr) 
# generate data 
set.seed(12345) 
df <- data.frame(date=seq(as.Date("2009/1/1"), by="day", length.out=1115),price=runif(1115, min=100, max=200)) 
# remove weekend days 
df <- df[!(weekdays(as.Date(df$date)) %in% c('Saturday','Sunday')),] 
# add some columns for later 
df$year <- as.numeric(format(as.Date(df$date), format="%Y")) 
df$month <- as.numeric(format(as.Date(df$date), format="%m")) 
df$day <- as.numeric(format(as.Date(df$date), format="%d")) 
df$daythisyear <- as.numeric(format(as.Date(df$date), format="%j")) 
df <- transform(df, doy = as.Date(paste(2000, month, day, sep="/"))) 
df <- ddply(df, .(year), transform, pctchg = ((price/price[1])-1)) 

Je me rends compte que je peux obtenir la variation annuelle (année en année) en utilisant une autre trame de données, quelque chose comme ceci:

df.yr <- ddply(df, .(year), function(x) (x[nrow(x),2]/x[1,2])-1) 

... mais je ne sais pas comment ajouter les chiffres pour les années à une colonne dans une trame de données existante, d'autant plus que (si vous travaillez avec 4 années de données) il n'y a que 4 lignes, une pour chaque année, par rapport à environ 800 dans la base de données des données quotidiennes utilisées pour dériver ces 4 lignes - vous obtenez une discordance.

Il est facile d'utiliser une boucle for à partir de la dernière rangée de la trame de données et remonter la colonne daythisyear pour y parvenir (si daythisyear sur la ligne actuelle est plus grande que daythisyear sur la ligne ci-dessous, vous avez un changement en année, prenez donc une nouvelle valeur à partir de cette ligne pour l'utiliser dans la colonne en cours d'ajout, etc.). Néanmoins, je suis sûr qu'il doit y avoir une approche plus R-familière en utilisant une fonction d'application ou ddply, que j'ai jusqu'ici soigneusement étudié. Donc ma question est:

Q. Comment puis-je calculer la variation annuelle de la valeur d'une colonne et ensuite insérer cette valeur, comme une nouvelle colonne, dans chaque ligne pour cette année?

+0

Je ne sais pas si je comprends bien votre question mais si je le fais, 'head (fusionner (df, df.yr, by =" année "))' pourrait donner ce que tu veux? – vaettchen

+0

vaettchen, merci pour cette suggestion. Cela semble également fonctionner et m'a montré un côté de «fusion» que je n'avais pas envisagé auparavant. – SlowLearner

Répondre

2

Je ne me suis pas encore converti en utilisateur ddply, préférant utiliser ave quand c'est la solution évidente. Je soupçonne que ce code traduirait à travers:

df$pctYrChng <- ave(df$price, df$year, FUN=function(x) tail(x,1)/head(x,1) - 1) 
unique(df$pctYrChng) 
#[1] -0.03259032 -0.05781901 0.35932519 0.04246669 
+0

Cela semble fonctionner comme demandé et avec une simplicité agréable. J'étais vaguement conscient de 'ave' mais je ne l'avais pas utilisé moi-même. Si cela peut se faire facilement en base R alors je ne ressens pas le besoin de chercher ailleurs! Merci, Dan – SlowLearner

+0

Je n'étais pas vraiment sûr de savoir si vous vouliez changer le YTD ou si vous vouliez le changement de day.one à day.last. Je vous ai donné la solution à la deuxième option, mais la solution à la première consiste simplement à substituer 'x' à' tail (x, 1) ' –

Questions connexes