R:改善工作流程并跟踪产出

时间:2013-05-31 19:08:22

标签: r workflow metadata

我认为这是一个很常见的问题,关于优化R中的工作流程。具体来说,我怎样才能避免出现文件夹满输出(绘图,RData文件,csv等)的常见问题,如果没有,过了一段时间,有一个线索,他们来自哪里或如何生产?在某种程度上,它肯定涉及尝试对文件夹结构进行智能化。我一直在四处寻找,但我不确定最佳策略是什么。到目前为止,我已经以一种相当简单(过度杀伤)的方式解决了这个问题:我创建了一个函数metainfo(见下文),该函数使用给定文件名的元数据编写文本文件。我们的想法是,如果生成一个绘图,则会发出此命令以生成一个文本文件,其文件名与绘图完全相同(当然,扩展名除外),其中包含有关系统,会话,已加载包的信息,R版本,函数和文件调用元数据函数等。问题是:

(i)人们如何处理这个普遍问题?有没有明显的方法可以避免我提到的问题?

(ii)如果没有,是否有人提出改进此功能的建议?目前它可能很笨重而且不理想。特别是,获取生成绘图的文件名不一定有效(我使用的解决方案是@hadley在1中提供的解决方案)。任何想法都会受到欢迎!

该函数假定git,因此请忽略产生的可能警告。这是主要功能,存储在文件metainfo.R

MetaInfo <- function(message=NULL, filename)
{
  # message  - character string - Any message to be written into the information
  #            file (e.g., data used).
  # filename - character string - the name of the txt file (including relative
  #            path). Should be the same as the output file it describes (RData,
  #            csv, pdf).
  #

  if (is.null(filename))
  {
    stop('Provide an output filename - parameter filename.')
  }

  filename <- paste(filename, '.txt', sep='')

  # Try to get as close as possible to getting the file name from which the
  # function is called.
  source.file <- lapply(sys.frames(), function(x) x$ofile)
  source.file <- Filter(Negate(is.null), source.file)
  t.sf <- try(source.file <- basename(source.file[[length(source.file)]]),
              silent=TRUE)

  if (class(t.sf) == 'try-error')
  {
    source.file <- NULL
  }

  func <- deparse(sys.call(-1)) 

  # MetaInfo isn't always called from within another function, so func could
  # return as NULL or as general environment.
  if (any(grepl('eval', func, ignore.case=TRUE)))
  {
    func <- NULL
  }

  time    <- strftime(Sys.time(), "%Y/%m/%d %H:%M:%S")
  git.h   <- system('git log --pretty=format:"%h" -n 1', intern=TRUE)
  meta <- list(Message=message,
               Source=paste(source.file, ' on ', time, sep=''),
               Functions=func,
               System=Sys.info(),
               Session=sessionInfo(),
               Git.hash=git.h)
  sink(file=filename)
  print(meta)
  sink(file=NULL)
}

然后可以在另一个函数中调用,存储在另一个文件中,例如:

source('metainfo.R')

RandomPlot <- function(x, y)
{
  fn <- 'random_plot'
  pdf(file=paste(fn, '.pdf', sep=''))
  plot(x, y)
  MetaInfo(message=NULL, filename=fn)
  dev.off()
}

x <- 1:10
y <- runif(10)

RandomPlot(x, y)

通过这种方式,可以生成与绘图具有相同文件名的文本文件,其中的信息可以帮助确定绘图的生成方式和位置。

5 个答案:

答案 0 :(得分:2)

有一个名为Project Template的软件包可以帮助组织和自动化典型的工作流程,包括R脚本,数据文件,图表等。还有许多有用的文档,例如Workflow of statistical data analysis by Oliver Kirchkamp

如果您使用Emacs和ESS进行分析,则必须学习Org-Mode。我用它来组织我的所有工作。以下是它与R集成的方式:R Source Code Blocks in Org Mode

还有一个名为Drake的新免费工具,它被宣传为“make for data”。

答案 1 :(得分:1)

就一般R组织而言:我喜欢使用单个脚本来重新创建项目的所有工作。任何项目都应该只需单击即可重现,包括与该项目相关的所有图表或论文。

因此,要保持井井有条:为每个项目保留一个不同的目录,每个项目都有自己的函数.R脚本存储与该项目关联的非包函数,每个项目都有一个像

## myproject
source("functions.R")
source("read-data.R")
source("clean-data.R")
等等......一路走来。这应该有助于保持一切井然有序,如果您获得新数据,您只需转到早期脚本来修复标题或其他内容,只需单击一下即可重新运行整个项目。

答案 2 :(得分:1)

我认为我的问题掩盖了一定程度的混乱。环顾四周,并探讨了迄今为止提供的建议,我得出的结论是,知道文件的生成位置和方式可能并不重要。实际上,您应该能够消除任何输出,并通过重新运行代码来重现它。因此,虽然我仍然可以使用上述功能获取额外信息,但实际上这是一个无情的问题,并且确实偶尔会清理文件夹。这些想法更加雄辩地解释here。这当然不排除使用Make / Drake或Project Template,我将尽力接受。再次感谢@noah和@alex的建议!

答案 3 :(得分:0)

现在还有一个R package called drake(R中的数据框为Make),独立于Factual的Drake。 R包也是一个类似Make的构建系统,它将代码/依赖关系与输出联系起来。

install.packages("drake") # It is on CRAN.
library(drake)
load_basic_example()
plot_graph(my_plan)
make(my_plan)

与它的前身remake一样,它还有额外的好处,你不必跟踪繁琐的文件堆。在R中生成的对象在make()期间被缓存,并且可以轻松重新加载。

readd(summ_regression1_small) # Read objects from the cache.
loadd(small, large) # Load objects into your R session.
print(small)

但您仍然可以将文件用作单引号目标。 (请参阅基本示例中的'report.Rmd'中的'report.md'my_plan。)

答案 4 :(得分:0)

RStudio 开发了一个名为 pins 的软件包可以解决这个问题。