如何以高效方式将列表对象(具有不同长度)转换为矩阵对象!以下示例澄清了上述目标:
假设您有一个结构列表对象:
l <- list(c(1,2), c(5,7,3,11))
print(l)
# [[1]]
# [1] 1 2
# [[2]]
# [1] 5 7 3 11
目标是以以下形式获得矩阵或data.frame:
[,1] [,2] [,3] [,4]
[1,] 1 2 NA NA
[2,] 5 7 3 11
使用for循环解决问题非常容易。您有什么想法,如何轻松地进行这种转换?提前谢谢!
答案 0 :(得分:3)
以下是一种方法:
n <- max(sapply(l, length))
t(sapply(l, function(x) if(length(x) < n) c(x, rep(NA, n - length(x))) else x))
[,1] [,2] [,3] [,4]
[1,] 1 2 NA NA
[2,] 5 7 3 11
首先,我们找出每个列表元素的最大向量长度,并将其存储在n
中(在这种情况下为4)。
然后,我们在列表上sapply
并检查列表元素的长度是否等于n
,如果是,则返回它,如果它短于{{1返回列表元素+ NA,重复频率差异。这将返回一个矩阵。我们在该矩阵上使用n
来转置它并获得所需的结果。
答案 1 :(得分:3)
您也可以尝试
t(sapply(l, `length<-`, max(sapply(l, length))))
# [,1] [,2] [,3] [,4]
#[1,] 1 2 NA NA
#[2,] 5 7 3 11
答案 2 :(得分:1)
如果您愿意使用套餐,您还可以考虑“stringi”套餐中的stri_list2matrix
:
library(stringi)
l <- list(c(1,2), c(5,7,3,11))
stri_list2matrix(l, byrow = TRUE)
# [,1] [,2] [,3] [,4]
# [1,] "1" "2" NA NA
# [2,] "5" "7" "3" "11"
关于有效 的问题,@ akrun的答案已经非常有效,但使用vapply
代替sapply
可以提高效率。 “stringi”方法也非常有效(并且有利于不使用像length<-
这样的神秘代码。)
funDD <- function() {
n <- max(sapply(l, length))
t(sapply(l, function(x) if(length(x) < n) c(x, rep(NA, n - length(x))) else x))
}
funAK <- function() t(sapply(l, `length<-`, max(sapply(l, length))))
funAM <- function() {
x <- max(vapply(l, length, 1L))
t(vapply(l, `length<-`, numeric(x), x))
}
funStringi <- function() stri_list2matrix(l, byrow = TRUE)
## Make a big list to test on
set.seed(1)
l <- lapply(sample(3:10, 1000000, TRUE), function(x) sample(10, x, TRUE))
system.time(out1 <- funDD())
# user system elapsed
# 5.81 0.33 7.02
library(microbenchmark)
microbenchmark(funAK(), funAM(), funStringi(), times = 10)
# Unit: seconds
# expr min lq mean median uq max neval
# funAK() 2.350877 2.499963 2.974141 3.123008 3.200545 3.418648 10
# funAM() 1.154151 1.238235 1.337607 1.287610 1.494964 1.508884 10
# funStringi() 2.080901 2.168248 2.352030 2.344763 2.462959 2.716910 10