Риски использования setwd() в скрипте?

Я слышал, что это плохая практика setwd() в сценарии.

  • Какие риски / опасности связаны с этим?
  • Какие есть лучшие альтернативы?

6 ответов

Решение

Это проблема воспроизводимого кода. Если вы укажете каталог, которого нет на чужом компьютере, он не сможет использовать ваш код. Это особенно плохо с абсолютными путями к файлам, и особенно плохо с путями к файлам Windows (которые абсолютно невозможно воспроизвести в системе Unix).

Мое предпочтительное решение состоит в том, чтобы указать, что пользователь должен находиться в соответствующем каталоге в собственной системе, прежде чем запускать код. Если для вашего удобства вы хотите поставить setwd(...) прямо в верхней части вашего кода, где другие люди могут заметить это и закомментировать его соответствующим образом, но остальная часть вашего кода предполагает только относительные пути из этого исходного каталога, это нормально для меня.

Ихуэй Се (автор knitr) Особенно сильно к этому относится:

https://groups.google.com/forum/?fromgroups=

Всякий раз, когда вы хотите манипулировать файлами, предполагается, что они находятся в одном и том же каталоге вашего источника (например, документы Rnw). Тогда вы всегда можете использовать относительные пути и вам никогда не понадобится setwd(). Использование setwd () противоречит принципу воспроизводимости, например, вы используете setwd('foo/bar/'), и каталог может не существовать на компьютерах других людей. Смотрите FAQ 7: https://github.com/yihui/knitr/blob/master/FAQ.md

И из вышеупомянутого FAQ 7:

Вам лучше этого не делать [изменить рабочий каталог внутри фрагментов кода knitr]. Ваш рабочий каталог всегда getwd() (все выходные файлы будут записаны здесь), но фрагменты кода оцениваются в каталоге, откуда поступает ваш входной документ. Изменение рабочих каталогов во время выполнения кода на R - это вообще плохая практика. Смотрите #38 для обсуждения. Вы также должны стараться по возможности избегать абсолютных каталогов (вместо этого используйте относительные каталоги), потому что это делает вещи менее воспроизводимыми.

Смотрите также: https://github.com/yihui/knitr/issues/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 - Проекты

Я обнаружил, что функциональность проектов RStudio очень важна для организации ваших файлов. Если другие пользователи также примут RStudio, у них будет приятное ощущение возможности открыть один файл ("*.Rproj") и загрузить проект в том же состоянии, в котором вы его сохранили в последний раз.

ProjectTemplate

Кроме того, я нашел новый инструмент 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 для каждой машины.

Для воспроизведения он не меняет чей-либо рабочий каталог, если только он не является тем конкретным пользователем.

Другие вопросы по тегам