代码之家  ›  专栏  ›  技术社区  ›  Roman LuÅ¡trik

改进了折叠数据帧列表的代码。

  •  8
  • Roman LuÅ¡trik  · 技术社区  · 14 年前

    亲爱的斯塔克弗沃斯(简称“花”),

    我有一个data.frames(walk.sample)列表,我想将其折叠成一个单独的(巨大的)data.frames。折叠时,我想标记(添加另一列)哪些行来自列表的哪个元素。这就是我目前所掌握的。

    这是需要折叠/堆叠的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()或其他更通用的函数更优雅地完成这个任务?

    2 回复  |  直到 14 年前
        1
  •  5
  •   Yorgos    14 年前

    我不是说这是最优雅的方法,但我认为这是可行的

    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)  ))
    
        2
  •  6
  •   Jonathan Chang    14 年前

    我想这会有用的…

    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)))