R中的命名空间和泛型函数

问题描述 投票:6回答:2

这个问题在某种程度上是对this question的跟进。请考虑以下示例

set.seed(1)
x <- cumsum(rnorm(10))
y <- stats::arima(x, order = c(1, 0, 0))
length(stats::fitted(y))
[1] 0

到目前为止很好:返回零因为R现在没有如何在类stats::fitted的对象上使用Arima

接下来在我的代码中,我需要forecast包中的一个函数。我没有附上包,我只是使用::notation加载它。在我下面的代码中,我将使用requireNamespace直接加载它。

requireNamespace("forecast", quietly = TRUE)
length(stats::fitted(y))
[1] 10

然后突然相同的命令返回不同的结果。我理解为什么会发生这种情况(我希望我说的正确):通过加载forecastpackage,将通用函数fitted(即fitted.Arima)的新方法加载到命名空间中,从而产生不同的结果。

对我来说这种行为非常烦人:有没有办法选择fitted的具体方法?我读了this chapter,但没有弄清楚如何规避这个问题。

我还尝试从命名空间卸载forecast包,但没有成功:

unloadNamespace("forecast")
length(stats::fitted(y))
[1] 10

似乎一旦我加载包我不能使用fitted的旧方法。我想知道如何处理这些情况。

EDIT

正如unloadNamespace("forecast")之后的评论中指出的那样,我明白了

isNamespaceLoaded("forecast")
[1] FALSE

methods适合仍然包括fitted.Arima

r namespaces
2个回答
5
投票

@CalumYou完全正确地指出卸载命名空间不会删除为另一个包中定义的S3泛型注册的S3方法。在这里,如果您感兴趣,可以更详细地了解这种情况的原因和原因。

加载预测包时,它定义的所有方法都在各种不同命名空间的数据库中“注册”。遵循的规则R是方法在定义其S3泛型的包的命名空间中注册。由于fitted()泛型是在统计数据中定义的,因此预测定义的新方法在.__S3MethodsTable__.环境中被注册。分离或卸载预测会使统计数据包保持不变(如果你考虑的话,可能是一个整体明智的设计决策),不幸的结果是fitted.Arima方法(以及许多其他方法)仍在其.__S3MethodsTable__中注册。

要了解情况,请查看以下内容:

isNamespaceLoaded("forecast")
## [1] FALSE
ls(stats:::.__S3MethodsTable__., pattern = "fitted")
## [1] "fitted.default"       "fitted.isoreg"        "fitted.kmeans"       
## [4] "fitted.nls"           "fitted.smooth.spline"

## Loading the forecast namespace registers new 'fitted' methods ...
requireNamespace("forecast", quietly = TRUE)
isNamespaceLoaded("forecast")
## [1] TRUE
ls(stats:::.__S3MethodsTable__., pattern = "fitted")
##  [1] "fitted.ar"              "fitted.Arima"           "fitted.arma"           
##  [4] "fitted.bats"            "fitted.default"         "fitted.ets"            
##  [7] "fitted.fracdiff"        "fitted.garch"           "fitted.gls"            
## [10] "fitted.glsStruct"       "fitted.gnls"            "fitted.gnlsStruct"     
## [13] "fitted.isoreg"          "fitted.kmeans"          "fitted.lagwalk"        
## [16] "fitted.lme"             "fitted.lmeStruct"       "fitted.lmList"         
## [19] "fitted.modelAR"         "fitted.nlmeStruct"      "fitted.nls"            
## [22] "fitted.nnetar"          "fitted.quantmod"        "fitted.smooth.spline"  
## [25] "fitted.tbats"           "fitted.tslm"            "fitted.values.quantmod"

## ... which are left behind even when the forecast namespace is unloaded
unloadNamespace("forecast")
isNamespaceLoaded("forecast")
## [1] FALSE
ls(stats:::.__S3MethodsTable__., pattern = "fitted")
##  [1] "fitted.ar"              "fitted.Arima"           "fitted.arma"           
##  [4] "fitted.bats"            "fitted.default"         "fitted.ets"            
##  [7] "fitted.fracdiff"        "fitted.garch"           "fitted.gls"            
## [10] "fitted.glsStruct"       "fitted.gnls"            "fitted.gnlsStruct"     
## [13] "fitted.isoreg"          "fitted.kmeans"          "fitted.lagwalk"        
## [16] "fitted.lme"             "fitted.lmeStruct"       "fitted.lmList"         
## [19] "fitted.modelAR"         "fitted.nlmeStruct"      "fitted.nls"            
## [22] "fitted.nnetar"          "fitted.quantmod"        "fitted.smooth.spline"  
## [25] "fitted.tbats"           "fitted.tslm"            "fitted.values.quantmod"

(有关问题和答案,see here。)


6
投票

我从R devel找到了this thread。 Brian Ripley(R Core)说:

卸载命名空间不会取消注册其方法(并且注册没有堆栈,因此R无法知道之前的内容)。

该线程然后注意到?unloadNamespace指向你在?detach

有关卸载和重新加载名称空间的一些问题,请参阅帮助中的注释以分离。

最终会说以下(强调我的)

如果一个包有一个命名空间,那么在默认情况下卸载它不会卸载命名空间(甚至可能没有unload = TRUE),并且分离通常不会卸载任何动态加载的编译代码(DLL)。此外,不会删除命名空间中注册的S3方法。

因此,我的理解是,在加载命名空间(例如使用::)注册S3方法时,这些方法永远不会链接到它们从中加载的命名空间,因此卸载名称空间也不能取消注册方法。从methods()清除它们的唯一方法是重启R.

作为RolandASc noted,如果你想避免派遣到stats:::fitted.default,你可以选择使用fitted.Arima调用默认方法。

© www.soinside.com 2019 - 2024. All rights reserved.