在R中隐藏个人功能
Posted
技术标签:
【中文标题】在R中隐藏个人功能【英文标题】:hiding personal functions in R 【发布时间】:2011-06-17 05:14:47 【问题描述】:我的 .Rprofile 中有一些便利功能,例如 handy function for returning the size of objects in memory。有时我喜欢在不重新启动的情况下清理我的工作区,我使用rm(list=ls())
执行此操作,这会删除我所有用户创建的对象和我的自定义函数。我真的不想破坏我的自定义功能。
解决此问题的一种方法似乎是使用我的自定义函数创建一个包,以便我的函数最终位于它们自己的命名空间中。这不是特别难,但是有没有更简单的方法来确保自定义函数不会被 rm() 杀死?
【问题讨论】:
【参考方案1】:将attach
和sys.source
组合到一个环境中并附加该环境。这里我在文件my_fun.R
中有两个函数:
foo <- function(x)
mean(x)
bar <- function(x)
sd(x)
在我加载这些函数之前,显然没有找到:
> foo(1:10)
Error: could not find function "foo"
> bar(1:10)
Error: could not find function "bar"
创建一个环境并将文件导入其中:
> myEnv <- new.env()
> sys.source("my_fun.R", envir = myEnv)
仍然不可见,因为我们没有附加任何东西
> foo(1:10)
Error: could not find function "foo"
> bar(1:10)
Error: could not find function "bar"
当我们这样做时,它们是可见的,并且因为我们已将环境的副本附加到搜索路径,所以函数在rm()
-ed 中仍然存在:
> attach(myEnv)
> foo(1:10)
[1] 5.5
> bar(1:10)
[1] 3.027650
> rm(list = ls())
> foo(1:10)
[1] 5.5
我仍然认为您最好使用自己的个人包裹,但同时上述内容可能就足够了。请记住,搜索路径上的副本就是副本。如果函数相当稳定并且您没有编辑它们,那么上面的方法可能有用,但如果您正在开发和修改函数,这可能比它的价值更麻烦。
第二种选择是将它们全部命名为.foo
而不是foo
,因为ls()
不会返回这样命名的对象,除非设置了参数all = TRUE
:
> .foo <- function(x) mean(x)
> ls()
character(0)
> ls(all = TRUE)
[1] ".foo" ".Random.seed"
【讨论】:
个人包对此很好,尽管我仍然很烦你必须跳过这么多圈来构建一个包。为什么我必须为个人包中的每个功能提供文档? 可能是因为我们不希望 CRAN 上出现未记录的包,如果 R Core 允许绕过某些检查,他们必须编写一大堆代码才能允许安装并加载一个有缺陷的包。提供了一些用户工具来帮助编写非正式的包——比如 roxygen——所以你维护一个源文件(没有 Rd 文件)并从中生成包文件。 而且您不必记录每个函数。只需将每个函数的 \alias 粘贴到单个帮助文件中,就足以使检查失败。你不需要 \usage 部分等,所以不要提供它们。在 NAMESPACES 被大量使用之前,这个技巧经常用于内部包函数。 @Gavin 当前的块不会阻止出现在 CRAN 上的未记录包。正如您所指出的,您可以提供它为空的文档。人们记录他们的工作,因为没有它发表将毫无意义。在我看来,如果希望在 CRAN 上满足某些标准,那么它们应该在进入 CRAN 时强制执行。当前的保姆方法只是对用户怀有敌意。 @Gavin 现在,这在您正在开发和重构现有代码的情况下很重要。是的,您可能使用了 \alias 技巧,但是如果您重命名和重构一堆函数会怎样。然后,您需要更新文档以匹配。然后您发现它不能满足您的需求,因此您尝试了其他方法,并且不得不再次更改文档。这些干扰使开发工作变得更加困难,我是以开发人员而不是统计学家的身份发言。【参考方案2】:与 Gavin 的回答类似,以下内容会加载一个函数文件,但不会留下额外的环境对象:
if('my_namespace' %in% search()) detach('my_namespace'); source('my_functions.R', attach(NULL, name='my_namespace'))
如果已附加命名空间的旧版本(对开发有用),这将删除旧版本,然后将一个名为 my_namespace
的空新环境和源 my_functions.R
附加到其中。如果您不删除旧版本,您将构建多个同名的附加环境。
如果您想查看已加载哪些函数,请查看输出
ls('my_namespace')
要卸载,请使用
detach('my_namespace')
这些附加的函数,就像一个包一样,不会被rm(list=ls())
删除。
【讨论】:
【参考方案3】:这里有两种方法:
1) 让每个函数名称都以点开头。例如.f
而不是 f
。 ls
不会列出此类函数,除非您使用 ls(all.names = TRUE)
,因此它们不会传递给您的 rm
命令。
或者,
2) 把它放在你的 .Rprofile 中
attach(list(
f = function(x) x,
g = function(x) x*x
), name = "MyFunctions")
这些函数将作为一个名为 "MyFunctions"
的组件出现在您的搜索列表中,而不是在您的工作区中,并且几乎可以像在您的工作区中一样访问它们。 search()
将显示您的搜索列表,ls("MyFunctions")
将列出您附加的函数的名称。由于它们不在您的工作区中,您通常使用的rm
命令不会删除它们。如果您确实希望删除它们,请使用detach("MyFunctions")
。
【讨论】:
【参考方案4】:第一个快速而肮脏的选择是在使用rm()
时使用lsf.str()
,以获取当前工作区中的所有功能。 ...并让您根据需要命名函数。
pattern <- paste0('*',lsf.str(), '$', collapse = "|")
rm(list = ls()[-grep(pattern, ls())])
我同意,这可能不是最佳做法,但它可以完成工作! (而且我必须有选择性地自己清理......)
【讨论】:
【参考方案5】:我发现当我创建或调试一个函数时,我的 R 环境经常会被各种对象弄得一团糟。我想要一种方法来有效地保持环境中没有这些物体,同时保留个人功能。
下面的简单功能是我的解决方案。它做了两件事: 1) 删除所有不以大写字母开头的非函数对象,然后 2) 将环境保存为 RData 文件
(需要 R.oo 包)
cleanup=function(filename="C:/mymainR.RData")
library(R.oo)
# create a dataframe listing all personal objects
everything=ll(envir=1)
#get the objects that are not functions
nonfunction=as.vector(everything[everything$data.class!="function",1])
#nonfunction objects that do not begin with a capital letter should be deleted
trash=nonfunction[grep('[[:lower:]]1',nonfunction)]
remove(list=trash,pos=1)
#save the R environment
save.image(filename)
print(paste("New, CLEAN R environment saved in",filename))
要使用此功能,必须始终遵守 3 条规则: 1) 将所有数据保留在 R 外部。 2) 对我希望永久可用的非功能对象使用以大写字母开头的名称。 3) 过时的功能必须用 rm 手动删除。
显然,这不是对每个人都适用的通用解决方案……如果您不遵守规则 #1 和 #2,则可能会造成灾难性的后果。但它确实有很多优点:a) 担心我的数据会被 cleanup() 破坏,这让我自律地只使用 R 作为处理器而不是数据库,b) 我的主要 R 环境非常小,我可以备份为电子邮件附件, c) 自动保存新功能(我不必手动管理个人功能列表)和 d) 保留对现有功能的所有修改。当然,最好的优势是最明显的……我不必花时间做 ls() 和审查对象来决定它们是否应该被 rm'd。
即使你不关心我的系统的细节,R.oo 中的“ll”功能对于这类事情也非常有用。它可用于实现几乎任何符合您个人编程风格的清理规则。
帕特里克·莫尔
【讨论】:
【参考方案6】:另一种选择:将函数保存在来自.RProfile
的单独文件中。您可以在闲暇时直接从 R 中重新获取内容。
【讨论】:
【参考方案7】:Gavin 的回答很精彩,我刚刚投了赞成票。只是为了完整,让我再扔一个:
R> q("no")
紧随其后
M-x R
创建一个新会话——它重新读取.Rprofile
。简单、快速、便宜。
除此之外,私人包是我书中的方式。
【讨论】:
假设一个在 ESS 中。我是谁。除非我不在。 但是它是一个 shell 提示,我们重新启动 littler。更快:)以上是关于在R中隐藏个人功能的主要内容,如果未能解决你的问题,请参考以下文章