在 R 中工作时,分离所有的包。

128

在解决另一个问题的过程中,我遇到了这个问题:

我可以通过以下方式删除所有 R 对象:

rm(list = ls(all = TRUE))

有没有相应的命令可以在工作会话期间分离已安装的软件包?

> sessionInfo()
R version 2.12.2 (2011-02-25)
Platform: i386-pc-mingw32/i386 (32-bit)

locale:
[1] LC_COLLATE=English_United States.1252 
[2] LC_CTYPE=English_United States.1252   
[3] LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C                          
[5] LC_TIME=English_United States.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base 

需要使用ggplot2库

Loading required package: ggplot2
Loading required package: reshape
Loading required package: plyr

Attaching package: 'reshape'

The following object(s) are masked from 'package:plyr':

    round_any

Loading required package: grid
Loading required package: proto

sessionInfo()

R version 2.12.2 (2011-02-25)
Platform: i386-pc-mingw32/i386 (32-bit)

locale:
[1] LC_COLLATE=English_United States.1252 
[2] LC_CTYPE=English_United States.1252   
[3] LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C                          
[5] LC_TIME=English_United States.1252    

attached base packages:
[1] grid      stats     graphics  grDevices utils     datasets  methods  
[8] base     

other attached packages:
[1] ggplot2_0.8.9 proto_0.3-9.1 reshape_0.8.4 plyr_1.4 

我尝试过这种方法,虽然它不是全局解决方案,但仍有效:

pkg <- c("package:ggplot2_0.8.9", "package:proto_0.3-9.1", "package:reshape_0.8.4",  "package:plyr_1.4")

 detach(pkg, character.only = TRUE)

Error in detach(pkg, character.only = TRUE) : invalid 'name' argument
In addition: Warning message:
In if (is.na(pos)) stop("invalid 'name' argument") :
  the condition has length > 1 and only the first element will be used

我需要的是类似于全局的东西:

  rm(list = ls(all = TRUE))

针对对象,预期不会删除附加的基础包

谢谢;


4
你的问题很合理,但为什么不直接重新启动R呢? - Aaron left Stack Overflow
5
@Aaron因为你不应该有太多的负担 ;-) 为了通过R CMD check测试,一个包需要能够干净地卸载自己,所以R核心团队期望这是可能的并且是人们希望做的事情。 - Gavin Simpson
@Aaron,我认为有时候在某些包可能会引起干扰的情况下,让会话继续进行可能是有用的,但这些包在之前的步骤中已经被使用过了... - John Clark
7
无法将R还原为初始状态。我与约翰·钱伯斯讨论过这个问题,特别是对于S4类/方法注册而言,这是一件特别困难的事情。 - hadley
11个回答

126

所以,应该有人简单地回答了以下问题。

lapply(paste('package:',names(sessionInfo()$otherPkgs),sep=""),detach,character.only=TRUE,unload=TRUE)

(编辑:2019年6月28日) 请使用最新版本的R 3.6.0。

invisible(lapply(paste0('package:', names(sessionInfo()$otherPkgs)), detach, character.only=TRUE, unload=TRUE))

请注意,使用invisible(*)并非必需,但可以防止NULL回复在R窗口中垂直地发送垃圾邮件。

(编辑:2019年9月20日)在版本3.6.1中

将仅已加载的names(sessionInfo()$loadedOnly)转换为显式附加的程序包可能很有帮助,然后再卸载这些程序包,如下所示。

lapply(names(sessionInfo()$loadedOnly), require, character.only = TRUE)
invisible(lapply(paste0('package:', names(sessionInfo()$otherPkgs)), detach, character.only=TRUE, unload=TRUE, force=TRUE))

通过 $basePkgs 可以尝试卸载基础包,还可以尝试使用 unloadNamespace(loadedNamespaces())。但是这些操作通常会出现错误,并可能破坏基本功能,例如导致 sessionInfo() 仅返回错误。这通常是由于原始包设计中缺乏可逆性导致的。目前,例如 timeDate 可能会发生不可逆转的错误。

(编辑:2020年9月24日) 对于版本4.0.2,以下首先加载要测试的包,然后给出一个序列来完全分离除“base”和“utils”包之外的所有包。强烈建议不要卸载这些包。

    invisible(suppressMessages(suppressWarnings(lapply(c("gsl","fBasics","stringr","stringi","Rmpfr"), require, character.only = TRUE))))
    invisible(suppressMessages(suppressWarnings(lapply(names(sessionInfo()$loadedOnly), require, character.only = TRUE))))
    sessionInfo()

    #the above is a test

    invisible(lapply(paste0('package:', c("stringr","fBasics")), detach, character.only=TRUE,unload=TRUE))
    #In the line above, I have inserted by hand what I know the package dependencies to be. A user must know this a priori or have their own automated
    #method to discover it. Without removing dependencies first, the user will have to cycle through loading namespaces and then detaching otherPkgs a
    #second time through.
    invisible(lapply(paste0('package:', names(sessionInfo()$otherPkgs)), detach, character.only=TRUE,unload=TRUE))

    bspkgs.nb<-sessionInfo()$basePkgs[sessionInfo()$basePkgs!="base"]
    bspkgs.nbu<-bspkgs.nb[bspkgs.nb!="utils"]
    names(bspkgs.nbu)<-bspkgs.nbu
    suppressMessages(invisible(lapply(paste0('package:', names(bspkgs.nbu)), detach, character.only=TRUE,unload=TRUE)))

    #again this thoroughly removes all packages and loaded namespaces except for base packages "base" and "utils" (which is highly not recommended).

3
我认为这篇文章值得点赞,因为它非常简洁,不需要额外的插件。 - Antonio Serrano
1
在最新版本的R 3.6.0中,应该使用以下代码:invisible(lapply(paste0('package:', names(sessionInfo()$otherPkgs)), detach, character.only=TRUE, unload=TRUE))请注意,使用invisible(*)并非必须,但可以防止NULL回复在窗口中垂直地产生垃圾信息。 - mmfrgmpds
使用invisible(lapply(paste0('package:', names(sessionInfo()$otherPkgs)), detach, character.only=TRUE, unload=TRUE))会导致Error in FUN(X[[i]], ...) : invalid 'name' argument错误。 - dvanic
当只有一个NULL值存在时,经常会出现“Error in FUN(X[[i]], ...)...”错误。可以使用“names(sessionInfo()$otherPkgs)”进行测试。如果返回“NULL”,则这是原因。 - mmfrgmpds
@mmfrgmpds,这在R版本4.1.0(2021-05-18)中根本不起作用。 - Krantz
显示剩余3条评论

62

请尝试这个:

detachAllPackages <- function() {

  basic.packages <- c("package:stats","package:graphics","package:grDevices","package:utils","package:datasets","package:methods","package:base")

  package.list <- search()[ifelse(unlist(gregexpr("package:",search()))==1,TRUE,FALSE)]

  package.list <- setdiff(package.list,basic.packages)

  if (length(package.list)>0)  for (package in package.list) detach(package, character.only=TRUE)

}

detachAllPackages()

4
如果你把 plyrdplyr 搞混了,似乎这是唯一的解决办法。谢谢! - JelenaČuklina
2
这适用于R 4.0.2,而其他解决方案似乎不行。 - dss

31

nothing

也许值得提一下Romain François提供的解决方案。当加载nothing包时,该包目前可在GitHub上获得,将卸载所有已加载的包;就像Romain提供的示例一样:

loadedNamespaces()
[1] "base"      "datasets"  "grDevices" "graphics"  "methods"   "stats"
[7] "utils"

require(nothing, quietly = TRUE)

loadedNamespaces()
[1] "base"

安装

使用devtools包:

devtools::install_github("romainfrancois/nothing")

pacman

另一种方法是使用CRAN提供的pacman包:

pacman::p_unload(pacman::p_loaded(), character.only = TRUE)

5
看一下这篇文章(http://trinker.github.io/pacman/vignettes/Introduction_to_pacman.html),也许 pacman::p_unload("all") 同样可行? - chandler
“nothing”可能是一个非常有用的小包,但它会删除“utils”,如果您尝试重新加载它,RStudio会崩溃。 - vorpal
@vorpal OP没有提到在RStudio中工作的事情,如果你恰好是使用RStudio、VSCode、Nvim-R或其他任何设置来使用R的话,自然而然地你可能愿意保持所需的包已加载。其他答案提供了实现这一点的方法。顺便说一句,我认为RStudio可能需要加载一些其他的包才能正常运行,比如rstudioapi和支持插件机制所需的任何内容。 - Konrad
吃豆人游戏对我无效,但是 require(nothing, quietly = TRUE) 有效!谢谢。 - LeMarque

28
你接近了答案。注意一下?detach对于detach()的第一个参数name所说的内容:

参数:

name: The object to detach.  Defaults to ‘search()[pos]’.  This can
      be an unquoted name or a character string but _not_ a
      character vector.  If a number is supplied this is taken as
      ‘pos’.
所以我们需要重复调用detach(),每个pkg元素调用一次。有几个其他参数需要指定才能使它起作用。第一个是 character.only = TRUE,这允许函数假设name是一个字符字符串 - 如果没有它,它将无法工作。其次,我们还可能想要取消加载任何关联的命名空间。这可以通过设置unload = TRUE来实现。因此,例如解决方案是:
pkg <- c("package:vegan","package:permute")
lapply(pkg, detach, character.only = TRUE, unload = TRUE)

以下是完整的示例:

> require(vegan)
Loading required package: vegan
Loading required package: permute
This is vegan 2.0-0
> sessionInfo()
R version 2.13.1 Patched (2011-09-13 r57007)
Platform: x86_64-unknown-linux-gnu (64-bit)

locale:
 [1] LC_CTYPE=en_GB.utf8       LC_NUMERIC=C             
 [3] LC_TIME=en_GB.utf8        LC_COLLATE=en_GB.utf8    
 [5] LC_MONETARY=C             LC_MESSAGES=en_GB.utf8   
 [7] LC_PAPER=en_GB.utf8       LC_NAME=C                
 [9] LC_ADDRESS=C              LC_TELEPHONE=C           
[11] LC_MEASUREMENT=en_GB.utf8 LC_IDENTIFICATION=C      

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods  
[7] base     

other attached packages:
[1] vegan_2.0-0   permute_0.7-0

loaded via a namespace (and not attached):
[1] grid_2.13.1     lattice_0.19-33 tools_2.13.1   
> pkg <- c("package:vegan","package:permute")
> lapply(pkg, detach, character.only = TRUE, unload = TRUE)
[[1]]
NULL

[[2]]
NULL

> sessionInfo()
R version 2.13.1 Patched (2011-09-13 r57007)
Platform: x86_64-unknown-linux-gnu (64-bit)

locale:
 [1] LC_CTYPE=en_GB.utf8       LC_NUMERIC=C             
 [3] LC_TIME=en_GB.utf8        LC_COLLATE=en_GB.utf8    
 [5] LC_MONETARY=C             LC_MESSAGES=en_GB.utf8   
 [7] LC_PAPER=en_GB.utf8       LC_NAME=C                
 [9] LC_ADDRESS=C              LC_TELEPHONE=C           
[11] LC_MEASUREMENT=en_GB.utf8 LC_IDENTIFICATION=C      

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods  
[7] base     

loaded via a namespace (and not attached):
[1] grid_2.13.1     lattice_0.19-33 tools_2.13.1

如果你想将这个代码块转换成函数,可以研究一下sessionInfo()中的代码,看看它是如何识别和标记"其他已加载的包"的。将其与上面的想法结合在一个单一函数内,你就完成了。不过,我会把那部分留给你自己。


14
您可以通过添加 pkgs = names(sessionInfo()$otherPkgs)pkgs = paste('package:', pkgs, sep = "") 来自动化此过程。 - Ramnath
3
@Ramnath +1 的确如此,但我不想帮助得太多了;-) - Gavin Simpson
4
如果软件包有依赖关系,您可能还希望添加 force=TRUE,以确保强制安装。 - James
@James,force = T 应该添加在哪里? - Ed_Gravy
1
@Ed_Gravy 这是传递给 detach() 的参数。 - Gavin Simpson

9
在基于Gavin的回答并且不完全是一个完整的函数的基础上,以下是这个序列:
sess.pkgs <- function (package = NULL) 
{   z <- list()
       if (is.null(package)) {
        package <- grep("^package:", search(), value = TRUE)
        keep <- sapply(package, function(x) x == "package:base" || 
            !is.null(attr(as.environment(x), "path")))
        package <- sub("^package:", "", package[keep])
    }
    pkgDesc <- lapply(package, packageDescription)
    if (length(package) == 0) 
        stop("no valid packages were specified")
    basePkgs <- sapply(pkgDesc, function(x) !is.null(x$Priority) && 
        x$Priority == "base")
    z$basePkgs <- package[basePkgs]
    if (any(!basePkgs)) {
        z$otherPkgs <-  package[!basePkgs]
    }
    z
}

lapply(paste("package:",sess.pkgs()$otherPkgs, sep=""), detach, 
                             character.only = TRUE, unload = TRUE)

2
不过有了你的答案,我终于可以用一行代码 lapply(paste("package:", names(sessionInfo()$otherPkgs), sep=""), detach, character.only = TRUE, unload = TRUE) 实现同样的功能。 - Ufos

4
#Detach all  packages
detachAllPackages <- function() {

  basic.packages <- c("package:stats","package:graphics","package:grDevices","package:utils","package:datasets","package:methods","package:base")

  package.list <- search()[ifelse(unlist(gregexpr("package:",search()))==1,TRUE,FALSE)]

  package.list <- setdiff(package.list,basic.packages)

  if (length(package.list)>0)  for (package in package.list) detach(package, character.only=TRUE)

}

detachAllPackages()

这将确保所有软件包都被分离,除了您的基本软件包。


这与@mjaniec的答案有何不同? - StupidWolf

4

如果您使用RStudio,只需在“Packages”选项卡中取消所有已选框以分离。


2
如果你有很多已加载的软件包,手动取消选中每一个会非常麻烦。 - SJ9

3

大多数情况下,这是plyrdplyr的问题。在代码开头使用以下内容:

detach("package:plyr", unload=TRUE)

所以每次运行脚本时,它都会清除plyr软件包。

0

结合各种答案的位,我找到了最健壮的解决方案...

packs <- c(names(sessionInfo()$otherPkgs), names(sessionInfo()$loadedOnly))
if(length(packs) > 0){ 
  message('Unloading packages -- if any problems occur, please try this from a fresh R session')
  while(length(packs) > 0){
    newpacks <- c()
    for(packi in 1:length(packs)){
      u=try(unloadNamespace(packs[packi]))
      if(class(u) %in% 'try-error') newpacks <- c(newpacks,packs[packi])
    }
    packs <- newpacks
    Sys.sleep(.1)
  }
}

0
为什么不用以下代码来删除所有附加包?
intialPackages = search() # added as 1st line of R script to get list of default packages
# below lines are added when newly attached packages needs to be removed
newPackages = search()[!(search() %in% intialPackages)]
try(sapply(newPackages, detach, character.only=TRUE, unload=TRUE, force=TRUE), silent=TRUE)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接