2011-02-09 32 views
2

我有一个由bigsplit()操作产生的列表列表(来自biganmory包的一部分biganalytics包)。如何在不使用lapply的情况下将列表列表转换为R中的稀疏矩阵?

每个列表都表示一个矩阵中的列,每个列表项都是二进制矩阵中值为1的索引。

将此列表变成稀疏二元(0/1)矩阵的最佳方法是什么? 在lapply()中使用lapply()是唯一的解决方案吗?我如何保留命名列表的因素作为列的名称?

+0

如果你能给一些示例数据,如有可能,可运行代码的形式,这将让生活轻松许多。所以你有列表(col1 = list(1,4),col2 = list(2,6,8),类似的东西? – 2011-02-09 08:53:18

+0

我的回复很慢,但你的回答非常好 - 谢谢!我在寻找 – Ron 2011-02-10 18:19:35

回答

2

您也可以考虑使用Matrix软件包,该软件包以比基R更高效的方式处理大型稀疏矩阵。您可以通过描述哪些行和列应该是1来构建0和1的稀疏矩阵。

library(Matrix) 
Test <- list(
    col1=list(2,4,7), 
    col2=list(3,2,6,8), 
    col3=list(1,4,5,3,7) 
) 
n.ids <- sapply(Test,length) 
vals <- unlist(Test) 
out <- sparseMatrix(vals, rep(seq_along(n.ids), n.ids)) 

结果是

> out 
8 x 3 sparse Matrix of class "ngCMatrix" 

[1,] . . | 
[2,] | | . 
[3,] . | | 
[4,] | . | 
[5,] . . | 
[6,] . | . 
[7,] | . | 
[8,] . | . 
0

以下是一些似乎适合您的描述的示例数据。

a <- as.list(sample(20, 5)) 
b <- as.list(sample(20, 5)) 
c <- as.list(sample(20, 5)) 
abc <- list(a = a, b = b, c = c) 

我不明白的方式与嵌套lapply()要做到这一点,但这里是另一种方式。这将是很好的消除unlist(),但也许别人可以改善这一点。

sp_to_bin <- function(splist) { 
    binlist <- numeric(100) 
    binlist[unlist(splist)] <- 1 
    return(binlist) 
} 
bindf <- data.frame(lapply(abc, sp_to_bin)) 
5

如果您需要矩阵,您可以在没有任何助手的情况下执行此操作。

说你有一个像这样构成的名单:

Test <- list(
    col1=list(2,4,7), 
    col2=list(3,2,6,8), 
    col3=list(1,4,5,3,7) 
) 

首先构造一个矩阵与正确的尺寸的零。如果你事先知道他们,那很简单。否则,你可以很容易地得出:

n.cols <- length(Test) 
n.ids <- sapply(Test,length) 
n.rows <- max(unlist(Test)) 
out <- matrix(0,nrow=n.rows,ncol=n.cols) 

然后你使用它的矩阵充满纵列计算有每个单元的指标的事实,成为一个:

id <- unlist(Test)+rep(0:(n.cols-1),n.ids)*n.rows 
out[id] <- 1 
colnames(out) <- names(Test) 

这给:

> out 
    col1 col2 col3 
[1,] 0 0 1 
[2,] 1 1 0 
[3,] 0 1 1 
[4,] 1 0 1 
[5,] 0 0 1 
[6,] 0 1 0 
[7,] 1 0 1 
[8,] 0 1 0 
+1

+1这很聪明很好的提醒你可以使用一维索引向量来分配(或从中提取)矩阵,填充预分配矩阵比其他方法快得多自然而然地想到涉及重复的`cbind`操作(例如使用`do.call(cbind,lapply(...))`)。 – 2011-02-09 13:50:30

2

使用Joris的例子,这是一个使用sapply/replace的句法简单的方法。我怀疑Joris的方法更快,因为它填充了一个预先分配的矩阵,而我的方法隐含地涉及到一堆列,因此需要为列重复分配内存(是这样吗?)。

Test <- list( 
col1=list(2,4,7), 
col2=list(3,2,6,8), 
col3=list(1,4,5,3,7) 
) 

> z <- rep(0, max(unlist(Test))) 
> sapply(Test, function(x) replace(z,unlist(x),1)) 
    col1 col2 col3 
[1,] 0 0 1 
[2,] 1 1 0 
[3,] 0 1 1 
[4,] 1 0 1 
[5,] 0 0 1 
[6,] 0 1 0 
[7,] 1 0 1 
[8,] 0 1 0 
+0

如果你有一个向量列表,你的代码会更快。返回一个错误:`错误在x [list] < - values:无效的下标类型'list'`。你必须改变c(x)到unlist(x)。 – 2011-02-09 22:42:57

0

要建立在里斯的答案,它使用了标索引向量来填充输出矩阵,你也可以使用一个矩阵指数矢量填补了输出矩阵;有时稍后可以更清楚地写或理解。

Test <- list(
    col1=list(2,4,7), 
    col2=list(3,2,6,8), 
    col3=list(1,4,5,3,7) 
) 

n.cols <- length(Test) 
n.ids <- sapply(Test,length) 
vals <- unlist(Test) 
n.rows <- max(vals) 
idx <- cbind(vals, rep(seq_along(n.ids), n.ids)) 
out <- matrix(0,nrow=n.rows,ncol=n.cols) 
out[idx] <- 1 
colnames(out) <- names(Test) 

结果是一样的。