如何将矩阵转换为R中的列向量列表?

Jor*_*eys 71 r list matrix

假设您要将矩阵转换为列表,其中列表的每个元素都包含一列.list()或者as.list()显然不起作用,直到现在我使用hack使用以下行为tapply:

x <- matrix(1:10,ncol=2)

tapply(x,rep(1:ncol(x),each=nrow(x)),function(i)i)
Run Code Online (Sandbox Code Playgroud)

我对此并不完全满意.谁知道我忽略了一种更清洁的方法?

(为了使列表填充行,代码显然可以更改为:

tapply(x,rep(1:nrow(x),ncol(x)),function(i)i)
Run Code Online (Sandbox Code Playgroud)

)

Tom*_*mmy 69

加文的回答简单而优雅.但是如果有很多列,那么更快的解决方案是:

lapply(seq_len(ncol(x)), function(i) x[,i])
Run Code Online (Sandbox Code Playgroud)

以下示例中的速度差异为6x:

> x <- matrix(1:1e6, 10)
> system.time( as.list(data.frame(x)) )
   user  system elapsed 
   1.24    0.00    1.22 
> system.time( lapply(seq_len(ncol(x)), function(i) x[,i]) )
   user  system elapsed 
    0.2     0.0     0.2 
Run Code Online (Sandbox Code Playgroud)

  • +1 关于各种解决方案的相对效率的好点。迄今为止最好的答案。 (2认同)

mds*_*ner 63

为了对cat进行外观处理,将数组视为向量,就像它没有dim属性一样:

 split(x, rep(1:ncol(x), each = nrow(x)))
Run Code Online (Sandbox Code Playgroud)

  • 这是'tapply`做的核心.但它更简单:).可能更慢但看起来很漂亮的解决方案是`split(x,col(x))`(和split(x,row(x))`分别). (8认同)
  • split(x,col(x))看起来更好 - 对向量的隐式强制很好... (2认同)
  • 经过大量测试后,这似乎工作得最快,特别是有很多行或列. (2认同)
  • 请注意,如果`x`具有列名,则`split(x,col(x,as.factor = TRUE))`将保留名称。 (2认同)

Ari*_*man 25

我相信,data.frames存储为列表.因此强制似乎是最好的:

as.list(as.data.frame(x))
> as.list(as.data.frame(x))
$V1
[1] 1 2 3 4 5

$V2
[1]  6  7  8  9 10
Run Code Online (Sandbox Code Playgroud)

基准测试结果很有意思.as.data.frame比data.frame更快,因为data.frame必须创建一个全新的对象,或者因为跟踪列名在某种程度上是昂贵的(见证c(unname())vs c()比较)?@Tommy提供的lapply解决方案速度提高了一个数量级.通过手动强制可以稍微改善as.data.frame()结果.

manual.coerce <- function(x) {
  x <- as.data.frame(x)
  class(x) <- "list"
  x
}

library(microbenchmark)
x <- matrix(1:10,ncol=2)

microbenchmark(
  tapply(x,rep(1:ncol(x),each=nrow(x)),function(i)i) ,
  as.list(data.frame(x)),
  as.list(as.data.frame(x)),
  lapply(seq_len(ncol(x)), function(i) x[,i]),
  c(unname(as.data.frame(x))),
  c(data.frame(x)),
  manual.coerce(x),
  times=1000
  )

                                                      expr     min      lq
1                                as.list(as.data.frame(x))  176221  183064
2                                   as.list(data.frame(x))  444827  454237
3                                         c(data.frame(x))  434562  443117
4                              c(unname(as.data.frame(x)))  257487  266897
5             lapply(seq_len(ncol(x)), function(i) x[, i])   28231   35929
6                                         manual.coerce(x)  160823  167667
7 tapply(x, rep(1:ncol(x), each = nrow(x)), function(i) i) 1020536 1036790
   median      uq     max
1  186486  190763 2768193
2  460225  471346 2854592
3  449960  460226 2895653
4  271174  277162 2827218
5   36784   37640 1165105
6  171088  176221  457659
7 1052188 1080417 3939286

is.list(manual.coerce(x))
[1] TRUE
Run Code Online (Sandbox Code Playgroud)

  • 相当于`manual.coerce(x)`可以是`unclass(as.data.frame(x))`. (2认同)

Rei*_*son 15

转换为数据框从那里到列表似乎工作:

> as.list(data.frame(x))
$X1
[1] 1 2 3 4 5

$X2
[1]  6  7  8  9 10
> str(as.list(data.frame(x)))
List of 2
 $ X1: int [1:5] 1 2 3 4 5
 $ X2: int [1:5] 6 7 8 9 10
Run Code Online (Sandbox Code Playgroud)


Sac*_*amp 11

使用plyr对于这样的事情非常有用:

library("plyr")

alply(x,2)

$`1`
[1] 1 2 3 4 5

$`2`
[1]  6  7  8  9 10

attr(,"class")
[1] "split" "list" 
Run Code Online (Sandbox Code Playgroud)


Dan*_*man 8

asplit一个矩阵转换为载体列表

asplit(x, 1) # split into list of row vectors
asplit(x, 2) # split into list of column vectors
Run Code Online (Sandbox Code Playgroud)


nbe*_*enn 6

新功能asplit()将在 v3.6 中基于 R。在那之前,本着与@mdsumner 的回答类似的精神,我们也可以这样做

split(x, slice.index(x, MARGIN))
Run Code Online (Sandbox Code Playgroud)

根据asplit(). 然而,如前所述,所有split()基于解决方案的解决方案都比@Tommy 的lapply/`[`. 这也适用于 new asplit(),至少在其当前形式中。

split_1 <- function(x) asplit(x, 2L)
split_2 <- function(x) split(x, rep(seq_len(ncol(x)), each = nrow(x)))
split_3 <- function(x) split(x, col(x))
split_4 <- function(x) split(x, slice.index(x, 2L))
split_5 <- function(x) lapply(seq_len(ncol(x)), function(i) x[, i])

dat <- matrix(rnorm(n = 1e6), ncol = 100)

#> Unit: milliseconds
#>          expr       min        lq     mean   median        uq        max neval
#>  split_1(dat) 16.250842 17.271092 20.26428 18.18286 20.185513  55.851237   100
#>  split_2(dat) 52.975819 54.600901 60.94911 56.05520 60.249629 105.791117   100
#>  split_3(dat) 32.793112 33.665121 40.98491 34.97580 39.409883  74.406772   100
#>  split_4(dat) 37.998140 39.669480 46.85295 40.82559 45.342010  80.830705   100
#>  split_5(dat)  2.622944  2.841834  3.47998  2.88914  4.422262   8.286883   100

dat <- matrix(rnorm(n = 1e6), ncol = 1e5)

#> Unit: milliseconds
#>          expr       min       lq     mean   median       uq      max neval
#>  split_1(dat) 204.69803 231.3023 261.6907 246.4927 289.5218 413.5386   100
#>  split_2(dat) 229.38132 235.3153 253.3027 242.0433 259.2280 339.0016   100
#>  split_3(dat) 208.29162 216.5506 234.2354 221.7152 235.3539 342.5918   100
#>  split_4(dat) 214.43064 221.9247 240.7921 231.0895 246.2457 323.3709   100
#>  split_5(dat)  89.83764 105.8272 127.1187 114.3563 143.8771 209.0670   100
Run Code Online (Sandbox Code Playgroud)


alf*_*ohm 5

我知道这是R中的诅咒,我并没有很多声誉支持这一点,但我发现for循环更有效率.我正在使用以下函数将矩阵mat转换为其列的列表:

mat2list <- function(mat)
{
    list_length <- ncol(mat)
    out_list <- vector("list", list_length)
    for(i in 1:list_length) out_list[[i]] <- mat[,i]
    out_list
}
Run Code Online (Sandbox Code Playgroud)

与mdsummer和原始解决方案相比的快速基准测试:

x <- matrix(1:1e7, ncol=1e6)

system.time(mat2list(x))
   user  system elapsed 
  2.728   0.023   2.720 

system.time(split(x, rep(1:ncol(x), each = nrow(x))))
   user  system elapsed 
  4.812   0.194   4.978 

system.time(tapply(x,rep(1:ncol(x),each=nrow(x)),function(i)i))
   user  system elapsed 
 11.471   0.413  11.817 
Run Code Online (Sandbox Code Playgroud)

  • Tommy的解决方案更快更紧凑:`system.time(lapply(seq_len(ncol(x)),function(i)x [,i]))用户:1.668系统:0.016已过去:1.693` (2认同)