【问题标题】:stack every n columns of a matrix without apply in R堆叠矩阵的每 n 列而不适用于 R
【发布时间】:2015-09-26 03:26:49
【问题描述】:

我有一个矩阵 Vmat:

    v1 = c(4  ,  8  ,  3 ,   5 ,   9)       
    v2 = c(5  ,  6  ,  6 ,  11  ,  6)
    v3 = c( 5  ,  6 ,   6 ,  11  ,  6)
    v4=  c(8, 6,  4, 4, 3)
    v5 =  c(4  ,  8  ,  3 ,   5  ,  9)
    v6=  c(8  ,  6  ,  4  ,  4 ,   3)
    v7 = c( 3 ,   2  ,  7   , 7 ,   4)
    v8=  c(3  ,  2   , 7   , 7  ,  4)

row1 = c(v1,v2)
row2 = c(v3,v4)

row3 = c(v5,v6)

row4 = c(v7,v8)

Vmat = rbind(row1,row2,row3,row4)


 Vmat
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
row1    4    8    3    5    9    5    6    6   11     6
row2    5    6    6   11    6    8    6    4    4     3
row3    4    8    3    5    9    8    6    4    4     3
row4    3    2    7    7    4    3    2    7    7     4

我想通过将矩阵分成 2 来堆叠矩阵(n=ncol(Vmat)/2 = 每 5 列)。

所以输出是:

 [,1] [,2] [,3] [,4] [,5] 
    4    8    3    5    9   
    5    6    6   11    6  
    4    8    3    5    9    
    3    2    7    7    4   
    5    6    6   11     6
    8    6    4    4     3
    8    6    4    4     3
    3    2    7    7     4

【问题讨论】:

  • 为什么apply不能用?
  • 因为它太慢了,矩阵很大,我正在做计算上非常需要的东西
  • 质量有多大?
  • 至少有 200 万列和 500 行,但这是“玩具”示例。真实的例子将更像是 2000 万行和 16000 行,甚至可能更大。我想尽可能快地对其进行预期编程
  • 有什么你自己已经尝试过的,所以我们知道什么不能做吗?我一直在玩弄它,但即使是您的“玩具”示例中的虚拟矩阵也会占用我几乎所有的 8GB RAM。

标签: r matrix dataframe


【解决方案1】:

这是一个潜在的 data.table 解决方案:

# install.packages("data.table", type="source")   # requires 1.9.6+
library(data.table)
vm  <- ncol(Vmat)/2
lst <- lapply(1:vm,function(i)c(i,i+vm))
result <- melt(as.data.table(Vmat),measure=lst)[,variable:=NULL]
result
#    value1 value2 value3 value4 value5
# 1:      4      8      3      5      9
# 2:      5      6      6     11      6
# 3:      4      8      3      5      9
# 4:      3      2      7      7      4
# 5:      5      6      6     11      6
# 6:      8      6      4      4      3
# 7:      8      6      4      4      3
# 8:      3      2      7      7      4

用一个更现实的例子:

set.seed(1)
Vmat <- matrix(sample(0:9,16e3*1000,replace=TRUE),nr=16e3)
library(data.table)
system.time({
  vm  <- ncol(Vmat)/2
  lst <- lapply(1:vm,function(i)c(i,i+vm))
  result <- melt(as.data.table(Vmat),measure=lst)[,variable:=NULL]
  })
#    user  system elapsed 
#     0.3     0.0     0.3 

因此,16,000 行 X 1000 列需要大约 0.3 秒。请注意,虽然此“使用 lapply(...)”,但它仅用于为 melt(...) 创建 measure.vars 列表,它完成了所有工作。

@Akrun 的解决方案(同系统):

system.time({
  n <- ncol(Vmat)/2
  ar1 <- array(Vmat, dim=c(nrow(Vmat),n,ncol(Vmat)/n))
  ar2 <- aperm(ar1, c(1,3,2))
  dim(ar2) <- c(prod(dim(ar1)[c(1,3)]),n)
})
#    user  system elapsed 
#    0.38    0.00    0.37 

all.equal(as.matrix(result),ar2,check.attributes=F)
# [1] TRUE

【讨论】:

  • 顺便说一句,检查你的输出的暗淡,你有更多的列。
  • 那为什么all.equal(...)返回TRUE?
  • dim(result)# [1] 32000 500; dim(ar2)# [1] 3200000 5 。如果您使用check.attributes=FALSE,我认为它不会检查尺寸。
  • 好的,所以也许我误解了这个问题。我以为 OP 想要 ncol(Vmat)/2 列??
  • OP 提到每 n 列,我认为您可能需要更改 vm 步骤。
【解决方案2】:

我们可以将matrix 转换为array,然后用aperm 转置数组,并更改维度。

n <- 5
ar1 <- array(Vmat, dim=c(nrow(Vmat),n,ncol(Vmat)/n))
ar2 <- aperm(ar1, c(1,3,2))
dim(ar2) <- c(prod(dim(ar1)[c(1,3)]),n)
ar2
#      [,1] [,2] [,3] [,4] [,5]
#[1,]    4    8    3    5    9
#[2,]    5    6    6   11    6
#[3,]    4    8    3    5    9
#[4,]    3    2    7    7    4
#[5,]    5    6    6   11    6
#[6,]    8    6    4    4    3
#[7,]    8    6    4    4    3
#[8,]    3    2    7    7    4

使用@jlhoward 的数据,

system.time({
  n <- 5
  ar1 <- array(Vmat, dim=c(nrow(Vmat),n,ncol(Vmat)/n))
  ar2 <- aperm(ar1, c(1,3,2))
 dim(ar2) <- c(prod(dim(ar1)[c(1,3)]),n)
})
# user  system elapsed 
# 0.265   0.015   0.279 

【讨论】:

  • 这不是用apply吗?如果矩阵很大,这会很慢吗?
  • 您无法比较跨系统的执行时间。您的方法在我的系统中运行时间为 0.38 秒,慢了大约 25%。
  • @jlhoward 我没有与您的方法进行比较。我试图估计我的方法运行的速度。它或多或少相似。
  • 1000 cols 的差异是微不足道的,但是对于 20MM cols(假设有足够的内存等),差异是相当大的。这两种方法的规模也可能不同。
  • @jlhoward 有可能,不过我只是对比了你展示的大数据。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多