list 如何将矩阵转换为 R 中的列向量列表?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6819804/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to convert a matrix to a list of column-vectors in R?
提问by Joris Meys
Say you want to convert a matrix to a list, where each element of the list contains one column. list()
or as.list()
obviously won't work, and until now I use a hack using the behaviour of tapply
:
假设您要将矩阵转换为列表,其中列表的每个元素都包含一列。list()
或者as.list()
显然不会工作,直到现在我使用以下行为进行黑客攻击tapply
:
x <- matrix(1:10,ncol=2)
tapply(x,rep(1:ncol(x),each=nrow(x)),function(i)i)
I'm not completely happy with this. Anybody knows a cleaner method I'm overlooking?
我对此并不完全满意。有人知道我忽略的更清洁的方法吗?
(for making a list filled with the rows, the code can obviously be changed to :
(为了制作一个充满行的列表,代码显然可以更改为:
tapply(x,rep(1:nrow(x),ncol(x)),function(i)i)
)
)
采纳答案by mdsumner
In the interests of skinning the cat, treat the array as a vector as if it had no dim attribute:
为了给猫剥皮,把数组当作一个向量,就好像它没有暗属性一样:
split(x, rep(1:ncol(x), each = nrow(x)))
回答by Tommy
Gavin's answer is simple and elegant. But if there are many columns, a much faster solution would be:
加文的回答简单而优雅。但是如果有很多列,一个更快的解决方案是:
lapply(seq_len(ncol(x)), function(i) x[,i])
The speed difference is 6x in the example below:
下例中的速度差为 6 倍:
> 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
回答by Ari B. Friedman
data.frames are stored as lists, I believe. Therefore coercion seems best:
我相信 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
Benchmarking results are interesting. as.data.frame is faster than data.frame, either because data.frame has to create a whole new object, or because keeping track of the column names is somehow costly (witness the c(unname()) vs c() comparison)? The lapply solution provided by @Tommy is faster by an order of magnitude. The as.data.frame() results can be somewhat improved by coercing manually.
基准测试结果很有趣。as.data.frame 比 data.frame 快,要么是因为 data.frame 必须创建一个全新的对象,要么是因为跟踪列名在某种程度上代价高昂(见证 c(unname()) 与 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
回答by Gavin Simpson
Converting to a data frame thence to a list seems to work:
将数据框转换为列表似乎有效:
> 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
回答by Sacha Epskamp
Using plyr
can be really useful for things like this:
使用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"
回答by alfymbohm
I know this is anathema in R, and I don't really have a lot of reputation to back this up, but I'm finding a for loop to be rather more efficient. I'm using the following function to convert matrix mat to a list of its columns:
我知道这是 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
}
Quick benchmark comparing with mdsummer's and the original solution:
与 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
回答by nbenn
The new function asplit()
will be coming to base R in v3.6. Up until then and in similar spirit to the answer of @mdsumner we can also do
新功能asplit()
将在 v3.6 中基于 R。在那之前,本着与@mdsumner 的回答类似的精神,我们也可以这样做
split(x, slice.index(x, MARGIN))
as per the docs of asplit()
. As previously shown however, all split()
based solutions are much slower than @Tommy's lapply/`[`
. This also holds for the new asplit()
, at least in its current form.
根据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
回答by wjchulme
There's a function array_tree()
in the tidyverse's purrr
package that does this with minimum fuss:
array_tree()
tidyverse 的purrr
包中有一个函数可以轻松完成此操作:
x <- matrix(1:10,ncol=2)
xlist <- purrr::array_tree(x, margin=2)
xlist
#> [[1]]
#> [1] 1 2 3 4 5
#>
#> [[2]]
#> [1] 6 7 8 9 10
Use margin=1
to list by row instead. Works for n-dimensional arrays. It preserves names by default:
使用margin=1
按行列表,而不是。适用于 n 维数组。它默认保留名称:
x <- matrix(1:10,ncol=2)
colnames(x) <- letters[1:2]
xlist <- purrr::array_tree(x, margin=2)
xlist
#> $a
#> [1] 1 2 3 4 5
#>
#> $b
#> [1] 6 7 8 9 10
(this is a near word-for-word copy of my answer to a similar question here)
(这是我回答的近字对字复制到类似的问题在这里)
回答by Daniel Freeman
Use asplit
to convert a matrix into a list of vectors
用asplit
一个矩阵转换为载体列表
asplit(x, 1) # split into list of row vectors
asplit(x, 2) # split into list of column vectors
回答by Zhilong Jia
convertRowsToList {BBmisc}
convertRowsToList {BBmisc}
Convert rows (columns) of data.frame or matrix to lists.
将 data.frame 或矩阵的行(列)转换为列表。
BBmisc::convertColsToList(x)
ref: http://berndbischl.github.io/BBmisc/man/convertRowsToList.html
参考:http: //berndbischl.github.io/BBmisc/man/convertRowsToList.html