【问题标题】:Split one row after every 3rd column and transport those 3 columns as a new row in r在每 3 列之后拆分一行并将这 3 列作为新行传输到 r
【发布时间】:2015-01-14 09:14:16
【问题描述】:

我有一个数据框,它是另一个命令的结果。这个数据框只有一行,大约有 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

我怎样才能意识到这一点?

【问题讨论】:

  • 听起来你应该修复造成问题的命令!你能解释一下你是如何最终得到一个超宽数据框的吗?
  • @A5C1D2H2I1M1N2O1R2T1,解析大文本或 html 文件可能会导致需要转置的超宽数据集。这并非闻所未闻。

标签: r split dataframe col


【解决方案1】:

试试

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

或者你可以直接在df上使用matrix

 as.data.frame(matrix(df, ncol=3, byrow=TRUE))

【讨论】:

  • 不确定第三个选项(或第一个)的附加值是什么:)
  • @David Arenburg 第三个选项显然很慢,因为我们正在使用t。我发布了第一个选项,然后意识到这可以在不使用 unlist 的情况下完成。
【解决方案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

【讨论】:

    【解决方案3】:

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

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

    1. 单行的未列出值。
    2. 一个分组变量,用于指示在最终输出中应将值分配给哪一行。
    3. 一个分组变量,用于指示在最终输出中应将值分配给哪一列。

    一旦你有了它,你就可以使用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

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

    【讨论】:

      猜你喜欢
      • 2021-01-07
      • 1970-01-01
      • 2016-05-08
      • 1970-01-01
      • 2011-09-21
      • 2016-11-14
      • 2016-11-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多