我试图将一个S4对象(Matrix
包中dgCMatrix
类的稀疏矩阵)传递给另一个包(Wrench
)中的一个函数。我得到了一些非常奇怪的行为,我很难理解。我怀疑这与R中的S3/S4方法调度有关,这是一个我不太理解的主题。
设置示例:
library(Matrix)
library(Wrench)
M <- Matrix(10 + 1:28, 4, 7)
M[, c(2,4:6)] <- 0
sM <- as(M, "sparseMatrix")
print(sM)
# 4 x 7 sparse Matrix of class "dgCMatrix"
#
# [1,] 11 . 19 . . . 35
# [2,] 12 . 20 . . . 36
# [3,] 13 . 21 . . . 37
# [4,] 14 . 22 . . . 38
print(rowSums(sM))
# [1] 65 68 71 74
接下来,我调用函数Wrench::wrench
来进行分析:
wrench(sM, colData=c('A','B','A','B','B','A','B'))
# Error in h(simpleError(msg, call)) :
# error in evaluating the argument 'i' in selecting a method for function '[': 'x' must be an array of at least two dimensions
奇怪...我在RStudio中的那一行设置了一个断点,进入wrench
,它开始如下:
function (mat, condition, etype = "w.marg.mean", ebcf = TRUE,
z.adj = FALSE, phi.adj = TRUE, detrend = FALSE, ...)
{
mat <- mat[rowSums(mat) > 0, ]
# ...
进入第一行,进入对rowSums(mat)
的调用,发现自己在base::rowSums
中。
function (x, na.rm = FALSE, dims = 1L)
{
if (is.data.frame(x))
x <- as.matrix(x)
if (!is.array(x) || length(dn <- dim(x)) < 2L)
stop("'x' must be an array of at least two dimensions")
is.data.frame(x)
是FALSE
,is.array(x)
是FALSE,调用了stop()
函数,错误就来自于此。好的,所以base::rowSums
不知道如何处理稀疏矩阵,并引发了错误...
但为什么在wrench
中调用rowSums(mat)
时会调用base::rowSums
,而在外部作用域中调用rowSums(sM)
时会调用Matrix::rowSums.dgCMatrix
,并且一切正常?
更一般地说,我如何调试这类问题,方法调度没有按预期发生(特别是在我无法控制的包中)?
我尝试过的其他事情:
- 我尝试使用
debugcall
,即外部作用域中的eval(debugcall(rowSums(sM)))
,它将我带到Matrix
中的某个地方,调用一些C代码,最终打印行和。当我在Wrench::wrench
中暂停调试器时尝试同样的事情时,我得到一个错误:
Browse[1]> eval(debugcall(rowSums(mat)))
Error in .signatureFromCall(func, mcall, env) :
trying to get slot "signature" from an object of a basic class ("function") with no slots
1条答案
按热度按时间jdzmm42g1#
您的
NAMESPACE
需要或
后者仅在必要时导入(鼓励您遵循此做法)。
至于调试,请注意,有几个附件将函数
wrench
的求值环境与其调用环境(在本例中是全局环境)分开:您可以通过递归调用
parent.env
来验证,如下所示:当您从Matrix导入
rowSums
的方法时,S4泛型rowSums
会被放置在您的包导入中。在base命名空间中,泛型rowSums
会在非泛型rowSums
之前找到,因为您的包导入会首先被搜索。调用时,泛型rowSums
从对应的方法表中分派一个合适的方法。如果找不到,则调用默认方法,对于rowSums
,该方法只是非泛型函数。重要的是,如果Wrench从Matrix导入,则加载Wrench会自动加载Matrix,因此Matrix导出的
rowSums
的方法在方法表中始终可用,供Wrench中的函数使用。这个例子的一个微妙的方面是,
[
运算符,与rowSums
不同,是 * 内部 * S4泛型。当您导入[
的方法时,S4泛型[
* 不会 * 放置在您的包导入中,但S4调度无论如何都可以工作。所以理论上你可以不用从Matrix导入
[
的方法,只要你从Matrix导入一些东西,以确保它的方法在加载Wrench时被加载。为了清楚起见,do 使用NAMESPACE
来导入你的包可能需要的所有方法。