转换为矩阵但在 R 中将一个对角线保留为 NULL
Convert to matrix but keep one diagonal to NULL in R
我有一个庞大的数据集,看起来像这样。
为了节省一些内存,我想计算成对距离但保留
矩阵的上对角线为 NULL。
library(tidyverse)
library(stringdist)
#>
#> Attaching package: 'stringdist'
#> The following object is masked from 'package:tidyr':
#>
#> extract
df3 <- tibble(fruits=c("apple","banana","ananas","apple","ananas","apple","ananas"),
position=c("135","135","135","136","137","138","138"),
counts = c(100,200,100,30,40,50,100))
stringdistmatrix(df3$fruits, method=c("osa"), nthread = 4) %>%
as.matrix()
#> 1 2 3 4 5 6 7
#> 1 0 5 5 0 5 0 5
#> 2 5 0 2 5 2 5 2
#> 3 5 2 0 5 0 5 0
#> 4 0 5 5 0 5 0 5
#> 5 5 2 0 5 0 5 0
#> 6 0 5 5 0 5 0 5
#> 7 5 2 0 5 0 5 0
由 reprex package (v2.0.1)
创建于 2022-03-01
然而,当我将 stringdistmatrix 转换为矩阵时(这一步对我来说很重要),
我的上对角线填满了数字。
有没有转换为矩阵但保持上对角线为NULL并节省内存的方法?
我希望我的数据看起来像这样
1 2 3 4 5 6
2 5
3 5 2
4 0 5 5
5 5 2 0 5
6 0 5 5 0 5
7 5 2 0 5 0 5
我认为您可能需要使用稀疏矩阵。包 Matrix
有这种可能性。您可以在以下位置了解有关稀疏矩阵的更多信息:Sparse matrix
library(Matrix)
m <- sparseMatrix(i = c(1:3, 2:3, 3), j=c(1:3,1:2, 1), x = 1, triangular = T)
m
#> 3 x 3 sparse Matrix of class "dtCMatrix"
#>
#> [1,] 1 . .
#> [2,] 1 1 .
#> [3,] 1 1 1
要检查矩阵的大小,可以使用函数 object.size
。
对于小矩阵,使用稀疏矩阵似乎没有什么区别,但是,对于大矩阵,节省内存是相当可观的:
library(Matrix)
n <- 30
m1 <- matrix(1,n,n)
m2 <- Matrix(m1, sparse = TRUE)
object.size(m1)
#> 7416 bytes
object.size(m2)
#> 7432 bytes
n <- 300
m1 <- matrix(1,n,n)
m2 <- Matrix(m1, sparse = TRUE)
object.size(m1)
#> 720216 bytes
object.size(m2)
#> 544728 bytes
如果您担心内存问题,那么 Matrix
可能不是答案,原因有二:
距离矩阵不稀疏。在 n
×n
距离矩阵中有 n*(n-1)/2
个非冗余元素,并且它们都可以是非零的。渐近地,那是一半的元素!将这些数据存储在 sparseMatrix
对象中是低效的,因为除了非零元素之外,您还需要存储它们在矩阵中的位置。长度为 n*(n-1)/2
的两个整数向量 i
和 j
将在内存中占用至少 4*n*(n-1)
字节(当 n = 5e+04
时约为 10 GB)。
Matrix
实现 class dspMatrix
以有效存储密集对称矩阵,包括距离矩阵。但是 dist
对象存储对角线下方的 n*(n-1)/2
元素,而 dspMatrix
对象存储那些元素 和 对角线元素。因此,如果不为新的 n*(n+1)/2
-length double 分配 4*n*(n+1)
字节(同样,当 n = 5e+04
时约 10 GB),您不能从 dist
强制转换为 dspMatrix
矢量.
最有效的方法是保留 dist
对象并根据您正在进行的任何计算的需要直接对其进行索引。
您可以利用以下事实:n
-by-n
距离矩阵的下三角中的元素 [i, j]
存储在相应 [=25] 的元素 [k]
中=] 对象,其中 k = i + (2 * (n - 1) - j) * (j - 1) / 2
.
例如,获取由dist
对象指定的距离矩阵的列(或行)j
x
无需构造整个矩阵,你可以使用这个函数:
getDistCol <- function(x, j) {
p <- length(x)
n <- as.integer(round(0.5 * (1 + sqrt(1 + 8 * p)))) # p = n * (n - 1) / 2
if (j == 1L) {
return(c(0, x[seq_len(n - 1L)]))
}
ii <- rep.int(j - 1L, j - 1L)
jj <- 1L:(j - 1L)
if (j < n) {
ii <- c(ii, j:(n - 1L))
jj <- c(jj, rep.int(j, n - j))
}
kk <- ii + ((2L * (n - 1L) - jj) * (jj - 1L)) %/% 2L
res <- double(n)
res[-j] <- x[kk]
res
}
fruits <- c("apple", "banana", "ananas", "apple", "ananas", "apple", "ananas")
x <- stringdist::stringdistmatrix(fruits)
## 1 2 3 4 5 6
## 2 5
## 3 5 2
## 4 0 5 5
## 5 5 2 0 5
## 6 0 5 5 0 5
## 7 5 2 0 5 0 5
getDistCol(x, 1L)
## [1] 0 5 5 0 5 0 5
lapply(1:7, getDistCol, x = x)
## [[1]]
## [1] 0 5 5 0 5 0 5
##
## [[2]]
## [1] 5 0 2 5 2 5 2
##
## [[3]]
## [1] 5 2 0 5 0 5 0
##
## [[4]]
## [1] 0 5 5 0 5 0 5
##
## [[5]]
## [1] 5 2 0 5 0 5 0
##
## [[6]]
## [1] 0 5 5 0 5 0 5
##
## [[7]]
## [1] 5 2 0 5 0 5 0
如果你坚持要一个dspMatrix
对象,那么你可以用这个方法强制从dist
:
library("Matrix")
asDspMatrix <- function(x) {
n <- attr(x, "Size")
i <- 1L + c(0L, cumsum(n:2L))
xx <- double(length(x) + n)
xx[-i] <- x
new("dspMatrix", uplo = "L", x = xx, Dim = c(n, n))
}
asDspMatrix(x)
## 7 x 7 Matrix of class "dspMatrix"
## [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## [1,] 0 5 5 0 5 0 5
## [2,] 5 0 2 5 2 5 2
## [3,] 5 2 0 5 0 5 0
## [4,] 0 5 5 0 5 0 5
## [5,] 5 2 0 5 0 5 0
## [6,] 0 5 5 0 5 0 5
## [7,] 5 2 0 5 0 5 0
我有一个庞大的数据集,看起来像这样。 为了节省一些内存,我想计算成对距离但保留 矩阵的上对角线为 NULL。
library(tidyverse)
library(stringdist)
#>
#> Attaching package: 'stringdist'
#> The following object is masked from 'package:tidyr':
#>
#> extract
df3 <- tibble(fruits=c("apple","banana","ananas","apple","ananas","apple","ananas"),
position=c("135","135","135","136","137","138","138"),
counts = c(100,200,100,30,40,50,100))
stringdistmatrix(df3$fruits, method=c("osa"), nthread = 4) %>%
as.matrix()
#> 1 2 3 4 5 6 7
#> 1 0 5 5 0 5 0 5
#> 2 5 0 2 5 2 5 2
#> 3 5 2 0 5 0 5 0
#> 4 0 5 5 0 5 0 5
#> 5 5 2 0 5 0 5 0
#> 6 0 5 5 0 5 0 5
#> 7 5 2 0 5 0 5 0
由 reprex package (v2.0.1)
创建于 2022-03-01然而,当我将 stringdistmatrix 转换为矩阵时(这一步对我来说很重要), 我的上对角线填满了数字。
有没有转换为矩阵但保持上对角线为NULL并节省内存的方法?
我希望我的数据看起来像这样
1 2 3 4 5 6
2 5
3 5 2
4 0 5 5
5 5 2 0 5
6 0 5 5 0 5
7 5 2 0 5 0 5
我认为您可能需要使用稀疏矩阵。包 Matrix
有这种可能性。您可以在以下位置了解有关稀疏矩阵的更多信息:Sparse matrix
library(Matrix)
m <- sparseMatrix(i = c(1:3, 2:3, 3), j=c(1:3,1:2, 1), x = 1, triangular = T)
m
#> 3 x 3 sparse Matrix of class "dtCMatrix"
#>
#> [1,] 1 . .
#> [2,] 1 1 .
#> [3,] 1 1 1
要检查矩阵的大小,可以使用函数 object.size
。
对于小矩阵,使用稀疏矩阵似乎没有什么区别,但是,对于大矩阵,节省内存是相当可观的:
library(Matrix)
n <- 30
m1 <- matrix(1,n,n)
m2 <- Matrix(m1, sparse = TRUE)
object.size(m1)
#> 7416 bytes
object.size(m2)
#> 7432 bytes
n <- 300
m1 <- matrix(1,n,n)
m2 <- Matrix(m1, sparse = TRUE)
object.size(m1)
#> 720216 bytes
object.size(m2)
#> 544728 bytes
如果您担心内存问题,那么 Matrix
可能不是答案,原因有二:
距离矩阵不稀疏。在
n
×n
距离矩阵中有n*(n-1)/2
个非冗余元素,并且它们都可以是非零的。渐近地,那是一半的元素!将这些数据存储在sparseMatrix
对象中是低效的,因为除了非零元素之外,您还需要存储它们在矩阵中的位置。长度为n*(n-1)/2
的两个整数向量i
和j
将在内存中占用至少4*n*(n-1)
字节(当n = 5e+04
时约为 10 GB)。Matrix
实现 classdspMatrix
以有效存储密集对称矩阵,包括距离矩阵。但是dist
对象存储对角线下方的n*(n-1)/2
元素,而dspMatrix
对象存储那些元素 和 对角线元素。因此,如果不为新的n*(n+1)/2
-length double 分配4*n*(n+1)
字节(同样,当n = 5e+04
时约 10 GB),您不能从dist
强制转换为dspMatrix
矢量.
最有效的方法是保留 dist
对象并根据您正在进行的任何计算的需要直接对其进行索引。
您可以利用以下事实:n
-by-n
距离矩阵的下三角中的元素 [i, j]
存储在相应 [=25] 的元素 [k]
中=] 对象,其中 k = i + (2 * (n - 1) - j) * (j - 1) / 2
.
例如,获取由dist
对象指定的距离矩阵的列(或行)j
x
无需构造整个矩阵,你可以使用这个函数:
getDistCol <- function(x, j) {
p <- length(x)
n <- as.integer(round(0.5 * (1 + sqrt(1 + 8 * p)))) # p = n * (n - 1) / 2
if (j == 1L) {
return(c(0, x[seq_len(n - 1L)]))
}
ii <- rep.int(j - 1L, j - 1L)
jj <- 1L:(j - 1L)
if (j < n) {
ii <- c(ii, j:(n - 1L))
jj <- c(jj, rep.int(j, n - j))
}
kk <- ii + ((2L * (n - 1L) - jj) * (jj - 1L)) %/% 2L
res <- double(n)
res[-j] <- x[kk]
res
}
fruits <- c("apple", "banana", "ananas", "apple", "ananas", "apple", "ananas")
x <- stringdist::stringdistmatrix(fruits)
## 1 2 3 4 5 6
## 2 5
## 3 5 2
## 4 0 5 5
## 5 5 2 0 5
## 6 0 5 5 0 5
## 7 5 2 0 5 0 5
getDistCol(x, 1L)
## [1] 0 5 5 0 5 0 5
lapply(1:7, getDistCol, x = x)
## [[1]]
## [1] 0 5 5 0 5 0 5
##
## [[2]]
## [1] 5 0 2 5 2 5 2
##
## [[3]]
## [1] 5 2 0 5 0 5 0
##
## [[4]]
## [1] 0 5 5 0 5 0 5
##
## [[5]]
## [1] 5 2 0 5 0 5 0
##
## [[6]]
## [1] 0 5 5 0 5 0 5
##
## [[7]]
## [1] 5 2 0 5 0 5 0
如果你坚持要一个dspMatrix
对象,那么你可以用这个方法强制从dist
:
library("Matrix")
asDspMatrix <- function(x) {
n <- attr(x, "Size")
i <- 1L + c(0L, cumsum(n:2L))
xx <- double(length(x) + n)
xx[-i] <- x
new("dspMatrix", uplo = "L", x = xx, Dim = c(n, n))
}
asDspMatrix(x)
## 7 x 7 Matrix of class "dspMatrix"
## [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## [1,] 0 5 5 0 5 0 5
## [2,] 5 0 2 5 2 5 2
## [3,] 5 2 0 5 0 5 0
## [4,] 0 5 5 0 5 0 5
## [5,] 5 2 0 5 0 5 0
## [6,] 0 5 5 0 5 0 5
## [7,] 5 2 0 5 0 5 0