J'essaie de créer une séquence d'années pour plusieurs ID dans R. Ma table d'entrée a une seule ligne pour chaque ID et donne un Start_year. Cela ressemble à ceci:
df %>% group_by(ID) %>% expand(year = Start_year:2015, Start_year) %>% select(-Start_year)
etc ...
J'ai besoin de créer un tableau avec plusieurs lignes pour chaque identifiant, montrant chaque année de leur Start_year jusqu'en 2015. Je vais ensuite l'utiliser pour rejoindre une autre table. Donc, dans mon exemple, ID1 aurait 17 lignes avec les années 1999: 2015. ID2 aurait 12 lignes 2004: 2015, ID3 aurait 1 ligne 2015 et ID4 aurait 9 lignes 2007: 2015.
Pour un sous-ensemble de mes données, je peux faire fonctionner cela en utilisant le code suivant:
ID Start_year 01 1999 02 2004 03 2015 04 2007
Cependant, mon ensemble de données complet contient environ 5 millions d'identifiants, et cette commande semble être extrêmement lente, prenant plusieurs heures.
Je suis donc recherche d'une implémentation plus rapide de cette commande dans R. D'après mon expérience, les commandes data.table semblent souvent être plus rapides que dplyr / tidyr - cependant, je ne connais pas du tout la syntaxe data.table.
3 Réponses :
Vous pourriez faire
text <- "ID Start_year 01 1999 02 2004 03 2015 04 2007" library(data.table) DT <- fread(text)
Dans votre cas, vous auriez probablement besoin de faire
library(readr); library(dplyr); library(tidyr) tbl <- read_table(text) tbl %>% group_by(ID) %>% mutate(Start_year = list(seq.int(Start_year, 2015L))) %>% # rename(new_col = Start_year) unnest()
A tidyverse manière de la même idée
setDT(df)[, .(col = seq.int(Start_year, 2015L)), by = ID]
data
out <- DT[, .(col = seq.int(Start_year, 2015L)), by = ID] out # ID col # 1: 1 1999 # 2: 1 2000 # 3: 1 2001 # 4: 1 2002 # 5: 1 2003 # 6: 1 2004 # 7: 1 2005 # 8: 1 2006 # 9: 1 2007 # ...
Hou la la! Merci, cela réalise la même chose en quelques secondes! On estimait que ma méthode précédente prenait 22 heures
une solution tidyverse pourrait être:
df <- data.table::fread(" ID Start_year 01 1999 02 2004 03 2015 04 2007") library(padr) library(tidyverse) df %>% pad_int('Start_year', end_val = 2015, group = "ID")
Si vous avez suffisamment de mémoire, vous pouvez prendre un ensemble complet d'ID x années et filtrer avec une jointure progressive:
res <- DT[ CJ(ID, Start_year = seq.int(min(Start_year), 2015L)), on=.(ID, Start_year), roll=TRUE, nomatch=0 ] setnames(res, "Start_year", "Year")[]
CJ
prend la "jointure croisée" du vecteur des identifiants et des années. Si vous n'êtes pas sur la dernière version de data.table, vous devrez peut-être nommer les deux arguments (par exemple, CJ (ID = ID, Start_year = seq.int (min (Start_year), 2015L))
).
Commentaire . L'OP dit que l'approche de @markus réduit déjà l'opération à quelques secondes, donc peut-être qu'une amélioration supplémentaire n'est pas nécessaire ... De plus, je ne suis pas vraiment sûr qu'il y ait des circonstances dans lesquelles mon approche serait plus rapide.