在每第3列之后拆分一行,并将这3列作为r中的新行传输

时间:2014-11-17 12:43:58

标签: r split dataframe col

我有一个数据框,它是另一个命令的结果。此数据框只有一行,大约有40000个条目。我的问题是3列是一组连接的数据。因此,我想在每第三列之后拆分行,并将其作为新行传输。例如:

创建测试数据框:

df=as.data.frame(matrix(seq(1:12), ncol=12, nrow=1))

现在我的数据框看起来像这样。

V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12
1  2  3  4  5  6  7  8  9  10  11  12

但我需要这样:

V1 V2 V3
1  2  3
4  5  6
7  8  9
10 11 12

我怎么能意识到这一点?

3 个答案:

答案 0 :(得分:4)

尝试

as.data.frame(matrix(unlist(df, use.names=FALSE),ncol=3, byrow=TRUE))
#  V1 V2 V3
#1  1  2  3
#2  4  5  6
#3  7  8  9
#4 10 11 12

或者您可以在matrix

上直接使用df
 as.data.frame(matrix(df, ncol=3, byrow=TRUE))

答案 1 :(得分:2)

还可以尝试使用dim<-(仅用于常识)

as.data.frame(t(`dim<-`(unlist(df), c(3, 4))))
#   V1 V2 V3
# 1  1  2  3
# 2  4  5  6
# 3  7  8  9
# 4 10 11 12

答案 2 :(得分:1)

事实证明这比我预期的要快(虽然仍然没有@akrun采用的明显方法那么快),所以我将发布这个(像大卫一样)“只是为了一般知识”。 (另外,“data.table”所有的东西。): - )

创建一个包含三列的data.table

  1. 单行的未列出值。
  2. 分组变量,用于指示在最终输出中应将值分配给哪一行。
  3. 分组变量,用于指示在最终输出中应将值分配给哪一列。
  4. 完成后,您可以使用dcast.data.table获取您提及的输出(加上奖励列)。

    对于上面的第2点,我们可以轻松定义类似以下的功能,以便轻松创建群组的过程:

    groupMaker <- function(vecLen, perGroup) {
      (0:(vecLen-1) %/% perGroup) + 1
    }
    

    然后我们可以按如下方式使用它:

    dcast.data.table(
      data.table(value = unlist(df, use.names = FALSE), 
                 row = groupMaker(ncol(df), 3), 
                 col = 1:3), 
      row ~ col)
    #    row  1  2  3
    # 1:   1  1  2  3
    # 2:   2  4  5  6
    # 3:   3  7  8  9
    # 4:   4 10 11 12
    

    现在,你提到你实际上正在处理单行~40K列data.frame(我假设它是39,999列,因为它可以很好地被3整除,我不想打破其他答案)。

    记住这一点,这里有一些(无用的)基准测试(没用,因为我们这里正在谈论毫秒)。

    set.seed(1)
    S <- sample(20, 39999, TRUE)
    S <- data.frame(t(S))
    
    funAM <- function(indf) {
      dcast.data.table(
        data.table(value = unlist(indf, use.names = FALSE), 
                   row = groupMaker(ncol(indf), 3), 
                   col = 1:3), 
        row ~ col)
    }
    
    funDA <- function(indf) {
      as.data.frame(t(`dim<-`(unlist(indf), c(3, ncol(indf)/3))))
    }
    
    funAK <- function(indf) as.data.frame(matrix(indf, ncol=3, byrow=TRUE))
    
    library(microbenchmark)
    microbenchmark(funAM(S), funDA(S), funAK(S))
    # Unit: milliseconds
    #      expr       min        lq      mean    median        uq      max neval
    #  funAM(S) 18.487001 18.813297 22.105766 18.999891 19.455812 50.25876   100
    #  funDA(S) 37.187177 37.450893 40.393893 37.870683 38.869726 94.20128   100
    #  funAK(S)  5.018571  5.149758  5.929944  5.271679  5.536449 26.93281   100
    

    如果 可能 有用,那么所需列的数量和输入列的数量不能很好地相互分割。

    例如,尝试以下示例数据:

    set.seed(1)
    S2 <- sample(20, 40000, TRUE)
    S2 <- data.frame(t(S))
    

    使用此示例数据:

    • funAM会为您提供warning,但会正确地将最后一行的最后两列显示为NA
    • funAK会给你一个warning,但会(可能)错误地回收最后一行的值。
    • funDA只会给你一个error

    我仍然认为你应该在源头解决问题: - )