6

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

我怎么能意识到这一点?

4

3 回答 3

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))
于 2014-11-17T12:46:57.883 回答
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
于 2014-11-17T12:56:23.873 回答
1

结果证明这比我预期的要快(尽管仍然没有@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.

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

于 2014-11-17T17:00:30.667 回答