[英]A fast way to rank each column in a sparse matrix
我有一个dgCMatrix
稀疏矩阵:
library(Matrix)
set.seed(1)
mat <- Matrix(c(0,0,2:0), 3,5)
rownames(mat) <- paste0("g",1:3)
colnames(mat) <- paste0("c",1:5)
我想以dplyr::dense_rank()
的方式对每一列进行降序排列,这样领带就会获得相同的排名,没有差距。
我正在寻找的 output 是一个data.frame
,其中每一行都有mat
的colnames
、 rownames
和rank
s。
我目前正在使用这个do.call
function:
library(dplyr)
df <- do.call(rbind,lapply(1:ncol(mat),function(x){
data.frame(cell=colnames(mat)[x],gene_name = rownames(mat),value=mat[,x]) %>%
dplyr::arrange(desc(value)) %>%
dplyr::mutate(rank=dplyr::dense_rank(desc(value)))
}))
但是寻找更快的东西。 我知道我的问题与这篇文章类似但不完全相同,因为这篇文章中使用的split
不保留rownames
。
从CsparseMatrix
到TsparseMatrix
并对结果进行操作在这里可能是最自然的:
library(Matrix)
set.seed(0)
m <- 6L
n <- 6L
x <- rsparsematrix(m, n, 0.5, rand.x = function(n) trunc(rnorm(n, 0, 2)))
dimnames(x) <- list(paste0("r", seq_len(m)), paste0("c", seq_len(n)))
x
6 x 6 sparse Matrix of class "dgCMatrix"
c1 c2 c3 c4 c5 c6
r1 0 -1 . -2 . 1
r2 . . -1 . 0 .
r3 . -2 . 0 0 .
r4 -2 1 . 0 . 0
r5 . 0 . 0 . .
r6 . . -1 2 . 0
denseRank <- function(x, ...) match(x, sort(unique(x), ...))
y <- as(x, "TsparseMatrix")
d <- data.frame(row = y@Dimnames[[1L]][y@i+1L],
col = y@Dimnames[[2L]][y@j+1L],
val = y@x,
ran = unsplit(lapply(split(y@x, y@j), denseRank, decreasing = TRUE, na.last = NA), y@j))
d
row col val ran
1 r1 c1 0 1
2 r4 c1 -2 2
3 r1 c2 -1 3
4 r3 c2 -2 4
5 r4 c2 1 1
6 r5 c2 0 2
7 r2 c3 -1 1
8 r6 c3 -1 1
9 r1 c4 -2 3
10 r3 c4 0 2
11 r4 c4 0 2
12 r5 c4 0 2
13 r6 c4 2 1
14 r2 c5 0 1
15 r3 c5 0 1
16 r1 c6 1 1
17 r4 c6 0 2
18 r6 c6 0 2
z <- y
z@x <- as.double(d$ran)
z
6 x 6 sparse Matrix of class "dgTMatrix"
c1 c2 c3 c4 c5 c6
r1 1 3 . 3 . 1
r2 . . 1 . 1 .
r3 . 4 . 2 1 .
r4 2 1 . 2 . 2
r5 . 2 . 2 . .
r6 . . 1 1 . 2
如果矩阵包含NA
,则需要小心。 以上将na.last = NA
传递给denseRank
,以便NA
值获得NA
排名; 这与dplyr::dense_rank
一致。 如果您希望为NA
值分配最低或最高等级,则必须分别传递na.last = FALSE
或na.last = TRUE
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.