2010-04-30 4 views
8

StackOverFlowers Chers (fleurs en bref),améliorer mon code pour plier une liste des data.frames

J'ai une liste de data.frames (walk.sample) que je voudrais effondrer en un seul (géant) trame de données. En s'effondrant, je voudrais marquer (en ajoutant une autre colonne) quelles lignes sont venues de quel élément de la liste. C'est ce que j'ai jusqu'ici.

Il s'agit du data.frame qui doit être réduit/empilé.

> walk.sample 
[[1]] 
    walker  x   y 
1073  3 228.8756 -726.9198 
1086  3 226.7393 -722.5561 
1081  3 219.8005 -728.3990 
1089  3 225.2239 -727.7422 
1032  3 233.1753 -731.5526 

[[2]] 
    walker  x   y 
1008  3 205.9104 -775.7488 
1022  3 208.3638 -723.8616 
1072  3 233.8807 -718.0974 
1064  3 217.0028 -689.7917 
1026  3 234.1824 -723.7423 

[[3]] 
[1] 3 

[[4]] 
    walker  x   y 
546  2 629.9041 831.0852 
524  2 627.8698 873.3774 
578  2 572.3312 838.7587 
513  2 633.0598 871.7559 
538  2 636.3088 836.6325 
1079  3 206.3683 -729.6257 
1095  3 239.9884 -748.2637 
1005  3 197.2960 -780.4704 
1045  3 245.1900 -694.3566 
1026  3 234.1824 -723.7423 

J'ai écrit une fonction pour ajouter une colonne qui dénotent de quel élément les lignes suivies sont venus annexant à un data.frame existant.

collapseToDataFrame <- function(x) { # collapse list to a dataframe with a twist 
    walk.df <- data.frame() 
    for (i in 1:length(x)) { 
     n.rows <- nrow(x[[i]]) 
     if (length(x[[i]])>1) { 
      temp.df <- cbind(x[[i]], rep(i, n.rows)) 
      names(temp.df) <- c("walker", "x", "y", "session") 
      walk.df <- rbind(walk.df, temp.df) 
     } else { 
      cat("Empty list", "\n") 
     } 
    } 
    return(walk.df) 
} 


> collapseToDataFrame(walk.sample) 
Empty list 
Empty list 
    walker   x   y session 
3   1 -604.5055 -123.18759  1 
60  1 -562.0078 -61.24912  1 
84  1 -594.4661 -57.20730  1 
9   1 -604.2893 -110.09168  1 
43  1 -632.2491 -54.52548  1 
1028  3 240.3905 -724.67284  1 
1040  3 232.5545 -681.61225  1 
1073  3 228.8756 -726.91980  1 
1091  3 209.0373 -740.96173  1 
1036  3 248.7123 -694.47380  1 

Je suis curieux de savoir si cela peut se faire de manière plus élégante, avec peut-être do.call() ou une autre fonction plus générique?

+0

Quelle est exactement la colonne de session? Pourquoi voulez-vous imprimer la liste vide à l'écran? – hadley

Répondre

5

Je ne prétends pas que ce soit l'approche la plus élégante, mais je pense qu'il travaille

library(plyr) 

ldply(sapply(1:length(walk.sample), function(i) 
      if (length(walk.sample[[i]]) > 1) 
      cbind(walk.sample[[i]],session=rep(i,nrow(walk.sample[[i]]))) 
    ),rbind) 

EDIT

Après avoir appliqué des remarques apt de Marek

do.call(rbind,lapply(1:length(walk.sample), function(i) 
      if (length(walk.sample[[i]]) > 1) 
      cbind(walk.sample[[i]],session=i) )) 
+1

'cbind' n'a pas besoin de réplication, vous pouvez simplement écrire' session = i'. Et sans plyr on pourrait utiliser 'do.call (rbind, sapply (......))'. – Marek

+0

Salut gd047, je voudrais juste mentionner que votre solution ne fonctionnerait pas lorsque le data.frame aura un nombre différent de lignes. En outre, lorsque le nombre de lignes est le même, les résultats ne sont pas correctes (il y a un mélange avec des lignes et des colonnes. Et aussi il n'y a pas de noms de colonnes) –

+0

Je pense que 'remplacer sapply' avec' lapply' peut aider. – Marek

6

I pense que cela fonctionnera ...

lengths <- sapply(walk.sample, function(x) if (is.null(nrow(x))) 0 else nrow(x)) 
cbind(do.call(rbind, walk.sample[lengths > 1]), 
     session = rep(1:length(lengths), ifelse(lengths > 1, lengths, 0))) 
+0

Vous devriez utiliser 'NROW' au lieu de' nrow'. Pour les données de question votre solution ne fonctionnera pas. – Marek

+0

Bonne capture, NROW est une solution possible, mais je ne sais pas quel est le comportement attendu lorsque vous avez une trame de données à une ligne. Je vais le changer en faisant une vérification NULL à la place ... –

+0

Bonne solution Jonathan! –

Questions connexes