我正在评估是否有一系列的路径及其基因包含在另一条路径中。所以我的想法是创建一个只做一个比较的函数。
all_in <- function(x, y) {
if (length(x) > length(y)) {
0
} else {
ifelse(all(x %in% y), 1, 0)
}
}然后Vectorize可以使用外部
all_in_vec <- Vectorize(all_in, vectorize.args = c("x", "y"))并以下列方式使用:
nested <- outer(paths2genes, paths2genes, all_in_vec)示例:
paths2genes <- structure(list(`1430728` = c("10", "9"), `156580` = c("10", "3",
"9"), `156582` = c("10", "9"), `194840` = c("2", "3"), `211859` = c("10",
"9")), .Names = c("1430728", "156580", "156582", "194840", "211859"
))测试:
library(testthat)
expect_true(all(diag(nested) == 1L))
expect_equal(nested[1, 2], 1L)然而,我最近发现,应该避免Vectorize,以支持内置的向量化。我遗漏了什么内置的方法吗?如何将此代码向量化?
发布于 2018-04-19 03:49:54
如果您要在您的cat("hello")函数的顶部添加一个all_in,您会发现您的函数被调用了25次,每次组合(对)路径都调用一次。因此,是的,尽管使用过Vectorized,但它本质上仍然是一个很大的旧循环。下面是编写向量化函数的方法,这样就只调用了一次或两次繁重的函数(%in%,或者在我的例子中是match):
all_in_outer <- function(list_x, list_y) {
uniq_x <- unique(unlist(list_x, use.names = FALSE))
len_x <- vapply(list_x, length, integer(1L))
as_mat <- function(list_a, ids = uniq_x) {
vec <- unlist(list_a, use.names = FALSE)
len <- vapply(list_a, length, integer(1L))
idx <- rep(seq_along(list_a), len)
mat <- matrix(0L, nrow = length(list_a), ncol = length(ids),
dimnames = list(names(list_a), ids))
mat[cbind(idx, match(vec, ids))] <- 1L
mat
}
(as_mat(list_x) %*% t(as_mat(list_y)) == len_x) * 1
}
all_in_outer(paths2genes, paths2genes)
# 1430728 156580 156582 194840 211859
# 1430728 1 1 1 0 1
# 156580 0 1 0 0 0
# 156582 1 1 1 0 1
# 194840 0 0 0 1 0
# 211859 1 1 1 0 1一些解释:当我们在第一个论点(10,9,3,2)中找到跨越所有通路的独特基因列表后,我们将这两个参数转化为一个矩阵A,如果路径i包含基因j,则为A[i,j] = 1,否则为0。对于paths2genes,这个矩阵是as_mat(paths2genes):
# 10 9 3 2
# 1430728 1 1 0 0
# 156580 1 1 1 0
# 156582 1 1 0 0
# 194840 0 0 1 1
# 211859 1 1 0 0然后,利用两个这样的矩阵之间的矩阵乘法,得到每个可能的组合路径的基因匹配数。然后,您只需将匹配的数量与路径的长度:(as_mat(list_x) %*% t(as_mat(list_y)) == len_x)进行比较即可。
在将每个输入转换为0和1的矩阵时,请参阅以下特定代码行:mat[cbind(idx, match(vec, ids))] <- 1L。这就是矩阵中填充的部分。通过对match的一次调用,它是完全矢量化的。
https://codereview.stackexchange.com/questions/192410
复制相似问题