2015-09-16 5 views
2

Je travaille avec un ensemble de données sur l'état de santé des patients au fil du temps. Je voudrais calculer la trame de données des transitions de l'état de santé actuel à l'état de santé suivant.Méthode efficace pour construire une trame de données de (état actuel, état suivant) dans R

Voici un exemple où l'état de santé est mesuré uniquement par le niveau et le poids de l'AFP. Les mesures de l'état de santé pourrait ressembler à ce qui suit:

x <- data.frame(id = c(1, 1, 1, 2, 2, 2), 
       day = c(1, 2, 3, 1, 2, 3), 
       event = c('status', 'status', 'death', 'status', 'status', 'status'), 
       afp = c(10, 50, NA, 20, 30, 40), 
       weight = c(100, 105, NA, 200, 200, 200)) 

La sortie souhaitée se présente comme suit:

y <- data.frame(id = c(1, 1, 2, 2), 
       current_afp = c(10, 50, 20, 30), 
       current_weight = c(100, 105, 200, 200), 
       next_event = c('status', 'death', 'status', 'status'), 
       next_afp = c(50, NA, 30, 40), 
       next_weight = c(105, NA, 200, 200)) 

Une façon inefficace pour obtenir la sortie est:

  • prendre la produit croisé du cadre de données de mesures avec lui-même
  • Conserver uniquement les lignes avec les ID correspondants et le jour .x + 1 = day.y
  • renomme les colonnes

Est-il possible d'obtenir la sortie plus efficace?

Note: Les mesures réelles trame de données peut avoir plus de 10 colonnes, il est donc pas très efficace à partir d'une ligne de perspective de code pour écrire explicitement

current_afp = x$afp[1:(n-1)], 
next_afp = x$afp[2:n] 
... 

et ainsi de suite.

Répondre

2

Vous pouvez essayer:

library(dplyr) 

x %>% 
    mutate_each(funs(lead(.)), -id, -day) %>% 
    full_join(x, ., by = c("id", "day")) %>% 
    select(-event.x) %>% 
    setNames(c(names(.)[1:2], 
      paste0("current_", sub("\\..*","", names(.)[3:4])), 
      paste0("next_", sub("\\..*","", names(.)[5:7])))) %>% 
    group_by(id) %>% 
    filter(day != last(day)) 

Ce qui donne:

# id day current_afp current_weight next_event next_afp next_weight 
#1 1 1   10   100  status  50   105 
#2 1 2   50   105  death  NA   NA 
#3 2 1   20   200  status  30   200 
#4 2 2   30   200  status  40   200 
+0

Cette réponse est utile car elle applique les idiomes 'dplyr' que je n'avais pas rencontrés auparavant. –

+0

@ILiketoCode Heureux que ça a aidé! –

1

en utilisant la base R avec une approche split-apply-combiner

res <- lapply(split(x[-2], x$id), function(y) { 
    xx <- cbind(y[1:(nrow(y)-1), ], y[2:nrow(y), -1]) 
    colnames(xx) <- c("id", paste("current", colnames(y)[-1], sep="_"), 
     paste("next", colnames(y)[-1], sep="_")) 
    xx[, which(colnames(xx) != "current_event")] 
}) 
do.call(rbind, res) 

    id current_afp current_weight next_event next_afp next_weight 
1 1   10   100  status  50   105 
2 1   50   105  death  NA   NA 
3 2   20   200  status  30   200 
4 2   30   200  status  40   200 

Ou, un exemple où tous les jours sont dans l'ordre

x <- data.frame(id = c(1, 1, 1, 2, 2, 2), 
      day = c(1, 2, 3, 1, 2, 4), 
      event = c('status', 'status', 'death', 'status', 'status', 'status'), 
      afp = c(10, 50, NA, 20, 30, 40), 
      weight = c(100, 105, NA, 200, 200, 200)) 
x 
    id day event afp weight 
1 1 1 status 10 100 
2 1 2 status 50 105 
3 1 3 death NA  NA 
4 2 1 status 20 200 
5 2 2 status 30 200 
6 2 4 status 40 200 

Certaines des transitions sont NA, qui peuvent être supprimées si vous le souhaitez.

res <- lapply(split(x, x$id), function(y) { 
    y <- merge(data.frame(id=unique(y$id), day = 1:max(y$day)), y, 
    by = c("id", "day"), all.x=TRUE)[, -2] 
    xx <- cbind(y[1:(nrow(y)-1), ], y[2:nrow(y), -1]) 
    colnames(xx) <- c("id", paste("current", colnames(y)[-1], sep="_"), 
     paste("next", colnames(y)[-1], sep="_")) 
    xx[, which(colnames(xx) != "current_event")] 
}) 
do.call(rbind, res) 
    id current_afp current_weight next_event next_afp next_weight 
1.1 1   10   100  status  50   105 
1.2 1   50   105  death  NA   NA 
2.1 2   20   200  status  30   200 
2.2 2   30   200  <NA>  NA   NA 
2.3 2   NA    NA  status  40   200