将巨大的稀疏矩阵转换为data.table,以便在R中更快地进行子集化

时间:2016-03-21 21:32:59

标签: r dataframe data.table tm

我遇到了一个大问题,一个更具体的问题,我希望 - 一旦解决 - 解决了更大的问题。如果有人对我有任何想法,我会非常感激。

基本上我有一个巨大的稀疏矩阵(大约300k x 150k,最初是用R的{tm}包创建的Term-Document矩阵),使用{slam}包保存为一个简单的三元组矩阵,我正在运行一个循环通过多组术语然后根据这些术语对其进行子集的函数。不幸的是,子集化过程非常慢。

在试图弄清楚如何更快地进行子集时,我偶然发现了data.table包,它在我运行的一些测试中表现得非常好。但是,当我尝试将我的稀疏矩阵转换为data.table时,我得到了

.Machine$integer.max

我理解这是因为它首先尝试将其转换为标准矩阵,从技术上讲,它是R的向量,300k * 150k远高于require(slam) STM <- simple_triplet_matrix(i = as.integer(runif(10000000,1,300000)), j = as.integer(runif(10000000,1,150000)), v = rep(rnorm(10), 1000000), nrow = 300000, ncol = 150000) start <- Sys.time() for (i in 1:10) { vec <- as.matrix(STM[,i]) } Sys.time() - start

所以我的问题:有没有人知道如何将一个简单的三元组矩阵转换为data.frame或data.table而不先将其转换为矩阵,从而避免整数溢出?

如果没有,是否有人a)有另一种解决方法或b)有关快速分组大型稀疏矩阵和/或简单三重矩阵的建议吗?

下面是一个可重复的例子。在我的机器上,循环(前10行中的每一行的子集)大约需要3秒。一旦我们进入数十万行的循环,就会很快变得令人望而却步。在此先感谢您的帮助:

STMm <- as.matrix(STM)

旁注:请注意,如果您尝试{{1}},我会得到上面显示的相同溢出错误。

2 个答案:

答案 0 :(得分:4)

STM对象实际上只是一个列表,您可以正常分组:

STM_DT <- data.table(i = STM$i, j = STM$j, v = STM$v)

这给出了:

> STM_DT
               i      j           v
       1: 186598    756  0.34271080
       2: 278329  72334  2.03924976
       3: 178388  32708  1.03925605
       4: 260635 101424  0.05780086
       5: 169321 126202  1.00027529
      ---                          
 9999996:  96209  90019 -1.09341023
 9999997:  54467  16612 -2.08070273
 9999998: 179029  96906 -0.86197333
 9999999: 153017 148731  0.47765003
10000000: 104145 123291  0.24258613

速度几乎是瞬间的

答案 1 :(得分:0)

很可能您需要这样的东西。

此示例最初是为解决更具体的问题而开发的,即如何将稀疏(但巨大)的模型矩阵附加到数据表。

# New Example
set.seed(0)
df = data.frame(matrix(letters[sample(4,15,replace=TRUE)],5))
mat = Matrix::sparse.model.matrix(~.-1,df)
mat

稀疏矩阵示例:

5 x 8 sparse Matrix of class "dgCMatrix"
  X1a X1b X1c X1d X2b X2c X3b X3c
1   .   1   .   .   1   .   1   .
2   1   .   .   .   .   .   .   1
3   .   .   .   1   .   1   .   1
4   .   .   1   .   .   1   .   .
5   1   .   .   .   1   .   .   .

print(object.size(mat))

3760字节

具有属性:

mat@i # 0-based row index

[1] 1 4 0 3 2 0 4 2 3 0 1 2

mat@p # 0-based column start

[1] 0 2 3 4 5 7 9 10 12

以下是如何转换为数据表:

# Conversion to Data Table
dt = data.table::data.table(matrix(FALSE,nrow(mat),ncol(mat)))
setnames(dt,colnames(mat))

for(cStart in 1:ncol(mat))
  set(dt, i = mat@i[(mat@p[cStart]:(mat@p[cStart+1L]-1L))+1L]+1L, 
j=colnames(mat)[cStart], value=TRUE)

print(object.size(dt))

2696字节

dt[,lapply(.SD, as.integer)]

返回所需的内容:

   X1a X1b X1c X1d X2b X2c X3b X3c
1:   0   1   0   0   1   0   1   0
2:   1   0   0   0   0   0   0   1
3:   0   0   0   1   0   1   0   1
4:   0   0   1   0   0   1   0   0
5:   1   0   0   0   1   0   0   0