2016-02-11 79 views
1

“a”是矩阵,“b”是数字。 “a”的行号与“b”的长度相同。将矩阵转换为R中的特定列表

a<-matrix(1:24,6,4,byrow = T) 
b<-c(3,1,2) 

我想将“a”转换为每个对象中元素数与“b”相同的列表。预期结果如下:

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

[[2]] 
    [,1] [,2] [,3] [,4] 
[1,] 13 14 15 16 

[[3]] 
    [,1] [,2] [,3] [,4] 
[1,] 17 18 19 20 
[2,] 21 22 23 24 

非常感谢您的帮助!

回答

6

这里,将根据b分裂a一个选项,因为这将返回原子向量的列表,我们lapply在它再次转换为matrix

lapply(split(a, rep(seq_along(b),b)), matrix, ncol = ncol(a)) 
#$`1` 
#  [,1] [,2] [,3] [,4] 
#[1,] 1 2 3 4 
#[2,] 5 6 7 8 
#[3,] 9 10 11 12 
# 
#$`2` 
#  [,1] [,2] [,3] [,4] 
#[1,] 13 14 15 16 
# 
#$`3` 
#  [,1] [,2] [,3] [,4] 
#[1,] 17 18 19 20 
#[2,] 21 22 23 24 

或者,如果你不介意的data.frame个列表则可能是:

split(as.data.frame(a), rep(seq_along(b),b)) 
1

我们可以使用split

split(as.data.frame(a),cumsum(c(TRUE,diff(sequence(b))!=1))) 
#$`1` 
# V1 V2 V3 V4 
#1 1 2 3 4 
#2 5 6 7 8 
#3 9 10 11 12 

#$`2` 
# V1 V2 V3 V4 
#4 13 14 15 16 

#$`3` 
# V1 V2 V3 V4 
#5 17 18 19 20 
#6 21 22 23 24 
+0

我得到不同的结果与您的代码 –

+0

@docendodiscimus你是对的。 – akrun

+0

我认为“c(1,b [-1]),c(b [-length(b)]”写错了 – lightsnail

3

您也可以使用mapply()这样的:

id <- mapply(seq, to=cumsum(b), length.out =b) 
lapply(id, function(i) a[i,, drop = FALSE]) 

或者,如果你想一气呵成:

mapply(function(i,j){a[seq(to=i, length.out = j),,drop=FALSE]}, 
      i = cumsum(b), 
      j = b) 

与使用lapply(split(...))相比,此解决方案快大约1.5倍。

a<-matrix(1:(87*400),87,400,byrow = TRUE) 
b<-c(3, 1, 2, 5, 2, 2, 1, 11, 19, 12, 9, 20) 

benchmark(
    { 
    id <- mapply(seq, to=cumsum(b), length.out =b) 
    lapply(id, function(i)a[i,, drop = FALSE]) 
    }, 
    { 
    lapply(split(a, rep(seq_along(b),b)), matrix, ncol = ncol(a)) 
    }, 
    replications = 10000 
) 

replications elapsed relative user.self sys.self user.child sys.child 
1  10000 3.53 1.000  3.53  0   NA  NA 
2  10000 6.02 1.705  5.95  0   NA  NA