2010-04-30 67 views
8

亲爱StackOverFlowers(简称花)的列表,提高我的代码崩溃data.frames

我有data.frames(walk.sample)的名单,我想折叠成一个单一的(巨)data.frame。在崩溃时,我想标记(添加另一列)哪些行来自列表的哪个元素。这是我到目前为止所做的。

这是需要折叠/堆叠的data.frame。

> 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 

我已经写了函数以添加表示从该元件的行进来,随后将其追加到现有data.frame的列。

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 

我很好奇,这是否可以更优雅的完成,也许do.call()或其他一些比较通用的功能?

+0

会话列究竟是什么?为什么你想要在屏幕上打印空白列表? – hadley 2010-04-30 12:35:44

回答

5

我不是说这是最优雅的方式,但我认为这是工作

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) 

编辑

应用马立克氏容易言论

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

'cbind'不需要复制,你可以写'session = i'。没有plyr,人们可以使用'do.call(rbind,sapply(......))'。 – Marek 2010-04-30 13:59:38

+0

嗨gd047,我只想提到你的解决方案不会工作时data.frame具有不同的行数。另外,当行数相同时,结果不正确(行与列混合使用,也没有列名) – 2010-04-30 14:30:05

+0

我认为用'lapply'替换'sapply'可能会有所帮助。 – Marek 2010-04-30 15:06:44

6

我后认为这将工作...

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

你应该使用'NROW'而不是'nrow'。对于来自问题的数据,您的解决方案将无法工 – Marek 2010-04-30 15:57:25

+0

良好的捕获,NROW是一种可能的解决方案,但我不知道当你有一行数据帧时预期的行为。我会通过做一个NULL检查来改变它... – 2010-04-30 16:04:46

+0

好的解决方案乔纳森! – 2010-04-30 19:55:09