如何选择一行,然后转置它,然后将其与R中的其余部分叠加?

时间:2016-03-18 00:14:20

标签: r data.table

假设我有这个数据集,

library(data.table)
mydata <- data.table(col1=c(11,21,31),
                             col2=c(12,22,32),
                             col3=c(13,23,33))

mydata 

       col1 col2 col3
    1:   11   12   13
    2:   21   22   23
    3:   31   32   33

我需要的是:

  • 选择第一行并移调它。
  • 然后,选择第二行将其堆叠在第一行下。
  • 然后,选择第三行将其堆叠在第二行......等。

我有1,135行。愚蠢的解决方案是手动执行此操作。例如,

mynewdata=t(data.frame(mydata[1,],mydata[2,],mydata[3,]))

mynewdata

            [,1]
    col1     11
    col2     12
    col3     13
    col1.1   21
    col2.1   22
    col3.1   23
    col1.2   31
    col2.2   32
    col3.2   33
直到,我到了第1,135行。我知道它必须涉及某种循环?但我不知道如何循环。提前谢谢。

3 个答案:

答案 0 :(得分:3)

基本上是一个带有行ID的melt操作。尝试:

out <- setkey(melt(mydata[,row := .I], id.vars="row"),row)
out

#   row variable value
#1:   1     col1    11
#2:   1     col2    12
#3:   1     col3    13
#4:   2     col1    21
#5:   2     col2    22
#6:   2     col3    23
#7:   3     col1    31
#8:   3     col2    32
#9:   3     col3    33

在基地R中,这是一个stack

out <- cbind(row=seq_len(nrow(mydata)),stack(mydata))
out[order(out$row),]

#  row values  ind
#1   1     11 col1
#4   1     12 col2
#7   1     13 col3
#2   2     21 col1
#5   2     22 col2
#8   2     23 col3
#3   3     31 col1
#6   3     32 col2
#9   3     33 col3

答案 1 :(得分:2)

  

我需要的是:

     
      
  • 选择第一行并移调它。
  •   
  • 然后,选择第二行将其堆叠在第一行下。
  •   
  • 然后,选择第三行将其堆叠在第二行......等等。
  •   

对于该任务,data.table包中的transpose函数可以提供帮助:

unlist(transpose(mydata))
# V11 V12 V13 V21 V22 V23 V31 V32 V33 
#  11  12  13  21  22  23  31  32  33

或者unlist(transpose(as.list(mydata)))

我想您可能想要跟踪此向量中的值来自的行和列,在这种情况下,您需要关注@ thelatemail的答案或手动构建所有内容:

data.table(
  values = unlist(transpose(mydata)),
  col    = seq_along(mydata),
  row    = rep(seq(nrow(mydata)), each = length(mydata))
)

#    values col row
# 1:     11   1   1
# 2:     12   2   1
# 3:     13   3   1
# 4:     21   1   2
# 5:     22   2   2
# 6:     23   3   2
# 7:     31   1   3
# 8:     32   2   3
# 9:     33   3   3

答案 2 :(得分:2)

R中通常的方法是“按行排名”,这是你似乎正在做的,是使用c(t(yourdata))方法:

c(t(mydata))
# [1] 11 12 13 21 22 23 31 32 33

如果您希望将其作为单个列矩阵,就像您在答案中所示,请执行:

matrix(c(t(mydata)))
#       [,1]
# [1,]   11
# [2,]   12
# [3,]   13
# [4,]   21
# [5,]   22
# [6,]   23
# [7,]   31
# [8,]   32
# [9,]   33

或者,如果您需要有关数据所来自的行和列的信息,您会有一点棘手:

do.call(CJ, lapply(dim(mydata), sequence))[, values := c(t(mydata))][]
#    V1 V2 values
# 1:  1  1     11
# 2:  1  2     12
# 3:  1  3     13
# 4:  2  1     21
# 5:  2  2     22
# 6:  2  3     23
# 7:  3  1     31
# 8:  3  2     32
# 9:  3  3     33

基准

这种相当手动的方法可以很快。

示例数据

set.seed(1)
nrow <- 100000
ncol <- 150
DT <- data.table(matrix(sample(100, nrow*ncol, TRUE), nrow = nrow))

<强> 功能

注意:我已经为funFrank添加了一些优化,使用上面的示例数据将其从约15秒减少到约1秒。优化包括在use.names = FALSE中使用unlist并使用seq_len代替seq

funAM <- function(indt) {
  setnames(do.call(CJ, lapply(dim(indt), seq_len)), 
           c("row", "col"))[, value := c(t(indt))][]
}

funThela <- function(indt) {
  setkey(melt(indt[,row := .I], id.vars="row"),row)[]
}

funFrank <- function(indt) {
  data.table(
    values = unlist(transpose(indt), use.names = FALSE),
    col    = seq_along(indt),
    row    = rep(seq_len(nrow(indt)), each = length(indt))
  )
}

<强> 结果

注意:我已将copy(DT)用于Thela的方法,因为他们在原始数据集上使用了:=来创建“行”列。

library(microbenchmark)
microbenchmark(funAM(DT), funThela(copy(DT)), funFrank(DT))
# Unit: milliseconds
#                expr      min        lq      mean    median        uq       max neval
#           funAM(DT) 163.7426  361.9589  388.9481  388.1012  425.0953  567.3669   100
#  funThela(copy(DT)) 583.5059  820.9864  881.4213  881.0558  949.5294 1109.9505   100
#        funFrank(DT) 866.5126 1109.7642 1201.5819 1176.9385 1292.6878 1633.0974   100
相关问题