2016-02-11 113 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