将巨大的稀疏矩阵转换为 data.table 以便在 R 中更快地进行子集化
Convert huge sparse matrix into data.table for faster subsetting in R
我有一个大问题,还有一个更具体的问题,我希望在解决后能够解决更大的问题。如果有人有任何想法让我尝试,我将不胜感激。
基本上我有一个巨大的稀疏矩阵(大约 300k x 150k,最初是使用 R 的 {tm} 包创建的术语文档矩阵),使用 {slam} 包保存为简单的三元组矩阵,我是运行 一个循环遍历术语集然后根据这些术语对其进行子集化的函数。不幸的是,子集化过程非常缓慢。
在试图弄清楚如何更快地进行子集化时,我偶然发现了 data.table 包,它在我 运行 的一些测试中表现非常好。但是,当我尝试将我的稀疏矩阵转换为 data.table 时,我得到
Error in vector(typeof(x$v), nr * nc) : vector size cannot be NA
In addition: Warning message:
In nr * nc : NAs produced by integer overflow
我理解这是因为它首先尝试将其转换为标准矩阵,从技术上讲这是 R 的向量,300k*150k 远高于 .Machine$integer.max
。
所以我的问题是:有谁知道如何将简单的三元组矩阵转换为 data.frame 或 data.table 而无需先将其转换为矩阵,从而避免整数溢出?
如果没有,是否有人 a) 有其他解决方法或 b) 对快速对巨大的稀疏矩阵 and/or 简单三重矩阵进行子集化有任何建议?
下面是一个可重复的例子。在我的机器上,对前 10 行中的每一行进行子集化的循环大约需要 3 秒。一旦我们开始遍历数十万行,那很快就会让人望而却步。在此先感谢您的帮助:
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
旁注:请注意,如果您尝试 STMm <- as.matrix(STM)
,您会得到与上面显示的相同的溢出错误。
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
速度几乎是瞬时的
您很可能需要这样的东西。
这个例子最初是为了解决一个更具体的问题,如何将稀疏(但巨大)模型矩阵附加到数据 table.
# 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
这里是如何转换为数据table:
# 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)]
Returns想要的:
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
我有一个大问题,还有一个更具体的问题,我希望在解决后能够解决更大的问题。如果有人有任何想法让我尝试,我将不胜感激。
基本上我有一个巨大的稀疏矩阵(大约 300k x 150k,最初是使用 R 的 {tm} 包创建的术语文档矩阵),使用 {slam} 包保存为简单的三元组矩阵,我是运行 一个循环遍历术语集然后根据这些术语对其进行子集化的函数。不幸的是,子集化过程非常缓慢。
在试图弄清楚如何更快地进行子集化时,我偶然发现了 data.table 包,它在我 运行 的一些测试中表现非常好。但是,当我尝试将我的稀疏矩阵转换为 data.table 时,我得到
Error in vector(typeof(x$v), nr * nc) : vector size cannot be NA
In addition: Warning message:
In nr * nc : NAs produced by integer overflow
我理解这是因为它首先尝试将其转换为标准矩阵,从技术上讲这是 R 的向量,300k*150k 远高于 .Machine$integer.max
。
所以我的问题是:有谁知道如何将简单的三元组矩阵转换为 data.frame 或 data.table 而无需先将其转换为矩阵,从而避免整数溢出?
如果没有,是否有人 a) 有其他解决方法或 b) 对快速对巨大的稀疏矩阵 and/or 简单三重矩阵进行子集化有任何建议?
下面是一个可重复的例子。在我的机器上,对前 10 行中的每一行进行子集化的循环大约需要 3 秒。一旦我们开始遍历数十万行,那很快就会让人望而却步。在此先感谢您的帮助:
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
旁注:请注意,如果您尝试 STMm <- as.matrix(STM)
,您会得到与上面显示的相同的溢出错误。
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
速度几乎是瞬时的
您很可能需要这样的东西。
这个例子最初是为了解决一个更具体的问题,如何将稀疏(但巨大)模型矩阵附加到数据 table.
# 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
这里是如何转换为数据table:
# 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)]
Returns想要的:
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