我听说它说setwd()
在脚本中使用是不好的做法。
- 与之相关的风险/危险是什么?
- 有什么更好的选择?
这是可重现代码的问题。如果您指定的目录在其他人的计算机上不存在,那么他们就无法使用您的代码。这对于绝对文件路径尤其糟糕,对于 Windows 文件路径尤其糟糕(在 Unix 系统上绝对不可能复制)。
我首选的解决方案是在开始运行代码之前指定用户应该位于他们自己系统上的相关目录中。如果为了您自己的方便,您想setwd(...)
在代码的顶部放置一个权利,其他人可以注意到它并酌情将其注释掉,但您的其余代码仅假定来自该起始目录的相对路径,这对我来说没问题.
谢一辉(作者knitr
)对此感觉特别强烈:
https://groups.google.com/forum/?fromgroups=#!topic/knitr/knM0VWoexT0
每当您要操作文件时,都假定它们位于源文件的同一目录下(例如 Rnw 文档)。然后你总是可以使用相对路径,你永远不需要 setwd()。使用 setwd() 与可再现性原则相矛盾,例如您使用 setwd('foo/bar/') 并且该目录可能不存在于其他人的计算机中。见FAQ 7: https ://github.com/yihui/knitr/blob/master/FAQ.md
从上述常见问题解答 7 中:
你最好不要这样做[更改 knitr 代码块中的工作目录]。您的工作目录始终是 getwd() (所有输出文件都将写入此处),但代码块在输入文档所在的目录下进行评估。在运行 R 代码时更改工作目录通常是一种不好的做法。参见#38 进行讨论。您还应该尽可能避免使用绝对目录(改用相对目录),因为它会使事情的可重复性降低。
我想不出setwd()
在我管理的服务器上运行的脚本中使用的任何特殊问题,因为它确实返回了一个可以被 try() 捕获的错误,并且您可以管理它。我setwd()
在对路径懒惰时使用过 - 见下文!
我file.path()
在脚本制作或其他方面广泛使用。处理输入目录中的文件并将输出图形和报告放在其他位置。所以类似于......(未经测试)这将是有点乏味使用setwd()
.
kInDir <- '~/Indir'
kOutDir <- '~/Outdir'
flist <- dir(path=kInDir, pattern='^[a-z]{2,5}\\.csv$')
# note I could have used full.names=T - but it's easier not to...
for (fnam in flist) {
# full path to the report file created
sfnam <- file.path(kOutDir, gsub('.csv', '_report.txt', fnam))
# full path to the csv file that will be created
ofnam <- file.path(kOutDir, gsub('.csv', '_b.csv', fnam))
#
# ok... we're going to process this CSV file...
r1 <- read.csv(file.path(kInDir, fnam))
#
# we''ll put the output from the analysis into this report file
sink(sfnam, split=TRUE)
# processs it... into a new data.frame k1
# blah blah blah...
#
write.csv(k1, file=ofnam, row.names=FALSE)
sink() # turn off this particular report file
}
走向更好的选择问题:
我主要将 R 用于单个项目(这意味着我是主要分析师)。但是,我们确实在有时需要与他人共享的项目中使用这些。
我发现RStudio的Projects 功能在保持文件井井有条方面大有帮助。如果其他用户也采用 RStudio,他们会很高兴能够打开单个文件 ("*.Rproj") 并以您上次保存的相同状态加载项目。
最重要的是,我发现了一个新工具,ProjectTemplate,它更进一步!作者开发的技术用于为您正在做的事情提供结构。请访问网站了解更多详情。
尽管 setwd() 的问题已成为目标,但我想在问题的替代部分中再添加一个。我们经常在相对路径很方便的地方使用 git
setrelwd <- function(rel_path){
curr_dir <- getwd()
abs_path <- file.path(curr_dir,rel_path)
if(dir.exists(abs_path)){
setwd(abs_path)
}
else
{
warning('Directory does not exist. Please create it first.')
}
}
> setrelwd("Summer2016")
Warning message:
In setrelwd("Summer2016") : Directory does not exist. Please create it first.
此外,如果您不想看到警告消息但立即创建文件夹,请参阅检查目录是否存在并在不存在时创建
为了让我工作的地方更便携,我们都把它放在一个 Rprofile 中
hdrive=
switch(Sys.info()[[1]],
'Linux'="/mnt/hdrive",
'Windows'="H:/",
"Darwin"="/Volumes/hdrive/mnt/hdrive"
)
所以我总是有这个变量来让我进入我们的共享驱动器。然后在我的脚本中我们可以写
setwd(paste(hdrive,"/relative/path/",sep="/"))
这样我们就可以解决其他人正在谈论的一些问题。
我个人添加了以下代码。我使用具有唯一信息的 Sys.info() 和 any()。
第一步是使用 Sys.info() 并找到您计算机的唯一标识符。
if(any(Sys.info() == "COMPUTER1")) {
setwd("c:/Users/user1/repos/project/")
}
if(any(Sys.info() == "COMPUTER2")) {
setwd("home/user1/repos/project/")
}
只需将计算机的名称添加到 if 语句并添加正确的路径即可。只需为每台机器添加一个新的 if。
对于复制,它不会更改任何人的工作目录,除非他们是该特定用户。