49 votes

Fenêtre coulissante R data.table

Quel est le meilleur moyen (le plus rapide) d'implémenter une fonction de fenêtre glissante avec le package data.table?

J'essaie de calculer une médiane mobile, mais plusieurs lignes par date (en raison de 2 facteurs supplémentaires), ce qui signifie que la fonction de zappage du zoo ne fonctionnerait pas. Voici un exemple utilisant une boucle for naïve:

 library(data.table)
df <- data.frame(
  id=30000,
  date=rep(as.IDate(as.IDate("2012-01-01")+0:29, origin="1970-01-01"), each=1000),
  factor1=rep(1:5, each=200),
  factor2=1:5,
  value=rnorm(30, 100, 10)
)

dt = data.table(df)
setkeyv(dt, c("date", "factor1", "factor2"))

get_window <- function(date, factor1, factor2) {
  criteria <- data.table(
    date=as.IDate((date - 7):(date - 1), origin="1970-01-01"),
    factor1=as.integer(factor1),
    factor2=as.integer(factor2)
  )
  return(dt[criteria][, value])
}

output <- data.table(unique(dt[, list(date, factor1, factor2)]))[, window_median:=as.numeric(NA)]

for(i in nrow(output):1) {
  print(i)
  output[i, window_median:=median(get_window(date, factor1, factor2))]
}
 

9voto

Matt Dowle Points 20936

data.table n'ont pas de caractéristiques particulières pour le déploiement de windows, à l'heure actuelle. Plus de détails ici, dans ma réponse à l'autre question similaire ici :

Est-il un rapide façon de faire un roulement de régression à l'intérieur des données.de la table?

Rouler la médiane est intéressant. Il aurait besoin d'une fonction spécialisée de le faire de façon efficace (même lien que dans le commentaire précédent) :

Rolling médiane de l'algorithme en C

L' data.table solutions dans la question et les réponses ici sont tous très inefficace, par rapport à un bon spécialisées rollingmedian de la fonction (qui n'est pas disponible pour R autant que je sache).

4voto

alan Points 810

J'ai réussi à obtenir l'exemple à 1,4 en créant un jeu de données décalé et en effectuant une jointure énorme.

 df <- data.frame(
  id=30000,
  date=rep(as.IDate(as.IDate("2012-01-01")+0:29, origin="1970-01-01"), each=1000),
  factor1=rep(1:5, each=200),
  factor2=1:5,
  value=rnorm(30, 100, 10)
)

dt2 <- data.table(df)
setkeyv(dt, c("date", "factor1", "factor2"))

unique_set <-  data.table(unique(dt[, list(original_date=date, factor1, factor2)]))
output2 <- data.table()
for(i in 1:7) {
  output2 <- rbind(output2, unique_set[, date:=original_date-i])
}    

setkeyv(output2, c("date", "factor1", "factor2"))
output2 <- output2[dt]
output2 <- output2[, median(value), by=c("original_date", "factor1", "factor2")]
 

Cela fonctionne assez bien sur cet ensemble de données de test, mais sur mon vrai, il échoue avec 8 Go de RAM. Je vais essayer de passer à l'une des instances High Memory EC2 (avec 17, 34 ou 68 Go de RAM) pour le faire fonctionner. Toutes les idées sur la façon de faire cela de manière moins intensive en mémoire seraient appréciées

0voto

Alan Points 876

Cette solution fonctionne mais cela prend du temps.

 df <- data.frame(
  id=30000,
  date=rep(seq.Date(from=as.Date("2012-01-01"),to=as.Date("2012-01-30"),by="d"),each=1000),
  factor1=rep(1:5, each=200),
  factor2=1:5,
  value=rnorm(30, 100, 10)
)

myFun <- function(dff,df){
    median(df$value[df$date>as.Date(dff[2])-8 & df$date<as.Date(dff[2])-1 & df$factor1==dff[3] & df$factor2==dff[4]])
}

week_Med <- apply(df,1,myFun,df=df)

week_Med_df <- cbind(df,week_Med)
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X