R:将3darray [i,j,]转换为df列,快速且可读

时间:2016-01-01 15:01:36

标签: arrays r

我正在使用三维数组,并希望沿着切片 前两个维度中每个位置的第三维作为数据框中的列。 我还希望我的代码对于那些不经常使用R的人来说是可读的。

在前两个维度上的循环非常易读但很慢(下面的示例为30秒),而置换 - 扁平 - 形状 - 矩阵方法 更快(14秒),但不那么可读。

对于一个好的解决方案的任何建议?

此处可重现的示例:

# Create data
    d1 <- 200
    d2 <- 100
    d3 <- 50
    data <- array(rnorm(n=d1*d2*d3), dim=c(d1, d2, d3))

# Idea 1: Loop
    df <- data.frame(var1 = rep(0, d3))
    i <- 1

    system.time(
    for (c in 1:d2) { 
        for(r in 1:d1){
          i <- i + 1
          df[[i]] <- data[r, c, ]
        }
    })

# Idea 2: Permute dimension of array first
    df2 <- data.frame(var1 = rep(0, d3))

    system.time({
    data.perm <- aperm(data, c(3, 1, 2))
    df2[, 2:(d1*d2 + 1)] <- matrix(c(data.perm), nrow = d3, ncol = d1*d2)}
    )

    identical(df, df2)

2 个答案:

答案 0 :(得分:1)

这是一个想法。推荐读物是Patrick Burns的The R Inferno(双关语意图?)。

myl <- vector("list", d3) #  create an empty list
i <- 1

system.time(
  for (c in 1:d2) { 
    for(r in 1:d1){
      i <- i + 1
      myl[[i]] <- data[r, c, ]
    }
  })

user  system elapsed 
 1.8     0.0     1.8 

# bind each list element into a matrix, column-wise
do.call("cbind", myl)[1:5, 1:5]

           [,1]       [,2]       [,3]       [,4]        [,5]
[1,] -0.3394909  0.1266012 -0.4240452  0.2277654 -2.04943585
[2,]  1.6788653 -2.9381127  0.5781967 -0.7248759 -0.19482647
[3,] -0.6002371 -0.3132874  1.0895175 -0.2766891 -0.02109013
[4,]  0.5215603 -0.2805730 -1.0325867 -1.5373842 -0.14034565
[5,]  0.6063638  1.6027835  0.5711185  0.5410889 -1.77109124

答案 1 :(得分:1)

我建议采用更简单的方法:

t(apply(data, 3, c))

我希望它符合您对快速可读的期望。

  • 快速 ,如下面的时间所示。
  • 可读 ,因为它是基本的apply语句。所有这一切都是使用c将每个第三维中的matrix转换为每个第三维中的单个向量,然后将其简化为二维array。结果只需要t ransposed ....

以下是您的示例数据:

set.seed(1)
d1 <- 200
d2 <- 100
d3 <- 50
data <- array(rnorm(n=d1*d2*d3), dim=c(d1, d2, d3))

以下是一些要比较的功能:

funam <- function() t(apply(data, 3, c))
funrl <- function() {
  myl <- vector("list", d3)
  i <- 1

  for (c in 1:d2) { 
    for(r in 1:d1){
      i <- i + 1
      myl[[i]] <- data[r, c, ]
    }
  }
  do.call(cbind, myl)
}

funop <- function() {
  df <- data.frame(var1 = rep(0, d3))
  i <- 1

  for (c in 1:d2) { 
    for(r in 1:d1){
      i <- i + 1
      df[[i]] <- data[r, c, ]
    }
  }
  df[-1]
}

以下是时间的结果:

system.time(am <- funam())
#    user  system elapsed 
#   0.000   0.000   0.062 
system.time(rl <- funrl())
#    user  system elapsed 
#   3.980   0.000   1.375 
system.time(op <- funop())
#    user  system elapsed 
#  21.496   0.000  21.355 

...和平等的比较:

all.equal(am, as.matrix(unname(op)), check.attributes = FALSE)
# [1] TRUE
all.equal(am, rl, check.attributes = FALSE)
# [1] TRUE