在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】:

attachsys.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 而不是 fls 不会列出此类函数,除非您使用 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中隐藏个人功能的主要内容,如果未能解决你的问题,请参考以下文章

个人永久性免费-Excel催化剂功能第44波-可见区域复制粘贴不覆盖隐藏内容

我发现了 GitHub 的一个隐藏功能

Terminal命令小结

隐藏个人设置邮件跟踪选项中的所有邮件这个选项的方法

Leetcode.831 隐藏个人信息

搭建个人服务器