保存然后加载 `tibble` 会导致 S4 方法无法识别它
Saving then loading a `tibble` causes it to be not recognised by S4 methods
我在 R 中遇到一个涉及 S4 class 系统的模糊问题。
首先我创建了一个 tibble 并保存它:
df = tibble::tibble(a=1:5, b=2:6)
save(df, file="foo.Rdata")
接下来,我关闭 R 会话,并启动一个新会话(出于某种原因,这很重要)。
然后,我定义了一个 S4 方法,它在 data.frame
上调度(tibble
是 class 的子class):
setGeneric("sumTheColumns", function(target){
standardGeneric("sumTheColumns")
})
setMethod("sumTheColumns", signature(target="data.frame"), function(target){
colSums(target)
})
load("foo.Rdata")
print(df)
print(class(df))
print(showMethods(sumTheColumns))
sumTheColumns(df)
据此,R 输出:
[1] "sumTheColumns"
a b
1 1 2
2 2 3
3 3 4
4 4 5
5 5 6
[1] "tbl_df" "tbl" "data.frame"
Function: sumTheColumns (package .GlobalEnv)
target="data.frame"
Error in (function (classes, fdef, mtable) :
unable to find an inherited method for function ‘sumTheColumns’ for signature ‘"tbl_df"’
Calls: sumTheColumns -> <Anonymous>
Execution halted
如您所见,tibble
已正确保存和加载,并且保留了 classes,但不再正确发送。有趣的是,如果您在我们创建 df
的第一个 R 会话中定义并调用这些相同的方法,这些方法会正确调度。
为什么会发生这种情况,我该如何解决?
如果这是 OS 特定的错误,这里是 sessionInfo
的一些输出:
> sessionInfo()
R version 4.1.1 (2021-08-10)
Platform: x86_64-conda-linux-gnu (64-bit)
Running under: Ubuntu 21.04
比较两种情况下的loadedNamespaces()
条目。我明白了
> loadedNamespaces()
[1] "compiler" "graphics" "utils" "grDevices" "stats" "datasets" "methods" "base"
在全新的 session 中,但在创建 df
之后,它增长到
> loadedNamespaces()
[1] "compiler" "magrittr" "ellipsis" "graphics" "pillar" "glue" "utils"
[8] "tibble" "grDevices" "crayon" "stats" "utf8" "fansi" "datasets"
[15] "vctrs" "methods" "lifecycle" "pkgconfig" "rlang" "base"
所以这些新软件包之一解决了这个问题。我猜是 tibble
本身,事实上我在新的 session 中看到了错误,但在我 运行 loadNamespace("tibble")
之后没有看到(它在第二个列表中得到了所有内容) .所以一个解决方案是:
要让您的数据框方法适用于 tibbles,您可以 运行
loadNamespace("tibble")
在给他们打电话之前。如果您打算将 tibbles 视为其他地方的 tibbles,则您会想要这样做,例如让他们以 tibbles 打印的方式打印。
或者,如果您只是想让您的代码像处理数据帧一样处理 tibbles,您可以执行 tibble
程序包的操作,并且 运行
methods::setOldClass(c("tbl_df", "tbl", "data.frame"))
这不会加载任何包,但会告诉 S4 系统小标题继承自数据帧。
我在 R 中遇到一个涉及 S4 class 系统的模糊问题。
首先我创建了一个 tibble 并保存它:
df = tibble::tibble(a=1:5, b=2:6)
save(df, file="foo.Rdata")
接下来,我关闭 R 会话,并启动一个新会话(出于某种原因,这很重要)。
然后,我定义了一个 S4 方法,它在 data.frame
上调度(tibble
是 class 的子class):
setGeneric("sumTheColumns", function(target){
standardGeneric("sumTheColumns")
})
setMethod("sumTheColumns", signature(target="data.frame"), function(target){
colSums(target)
})
load("foo.Rdata")
print(df)
print(class(df))
print(showMethods(sumTheColumns))
sumTheColumns(df)
据此,R 输出:
[1] "sumTheColumns"
a b
1 1 2
2 2 3
3 3 4
4 4 5
5 5 6
[1] "tbl_df" "tbl" "data.frame"
Function: sumTheColumns (package .GlobalEnv)
target="data.frame"
Error in (function (classes, fdef, mtable) :
unable to find an inherited method for function ‘sumTheColumns’ for signature ‘"tbl_df"’
Calls: sumTheColumns -> <Anonymous>
Execution halted
如您所见,tibble
已正确保存和加载,并且保留了 classes,但不再正确发送。有趣的是,如果您在我们创建 df
的第一个 R 会话中定义并调用这些相同的方法,这些方法会正确调度。
为什么会发生这种情况,我该如何解决?
如果这是 OS 特定的错误,这里是 sessionInfo
的一些输出:
> sessionInfo()
R version 4.1.1 (2021-08-10)
Platform: x86_64-conda-linux-gnu (64-bit)
Running under: Ubuntu 21.04
比较两种情况下的loadedNamespaces()
条目。我明白了
> loadedNamespaces()
[1] "compiler" "graphics" "utils" "grDevices" "stats" "datasets" "methods" "base"
在全新的 session 中,但在创建 df
之后,它增长到
> loadedNamespaces()
[1] "compiler" "magrittr" "ellipsis" "graphics" "pillar" "glue" "utils"
[8] "tibble" "grDevices" "crayon" "stats" "utf8" "fansi" "datasets"
[15] "vctrs" "methods" "lifecycle" "pkgconfig" "rlang" "base"
所以这些新软件包之一解决了这个问题。我猜是 tibble
本身,事实上我在新的 session 中看到了错误,但在我 运行 loadNamespace("tibble")
之后没有看到(它在第二个列表中得到了所有内容) .所以一个解决方案是:
要让您的数据框方法适用于 tibbles,您可以 运行
loadNamespace("tibble")
在给他们打电话之前。如果您打算将 tibbles 视为其他地方的 tibbles,则您会想要这样做,例如让他们以 tibbles 打印的方式打印。
或者,如果您只是想让您的代码像处理数据帧一样处理 tibbles,您可以执行 tibble
程序包的操作,并且 运行
methods::setOldClass(c("tbl_df", "tbl", "data.frame"))
这不会加载任何包,但会告诉 S4 系统小标题继承自数据帧。