[r] 다른 스크립트에 (소스) R 스크립트를 포함하는 방법

프로젝트의 다른 스크립트에서 사용하려는 유틸리티 R 스크립트 util.R을 만들었습니다. 이 스크립트가 정의하는 함수를 다른 스크립트에서 작동 할 수 있도록하는 적절한 방법은 무엇입니까?

require아직로드되지 않은 경우에만 패키지를로드하는 함수 와 유사한 것을 찾고 있습니다. 호출 source("util.R")할 때마다 스크립트를로드하므로 호출하고 싶지 않습니다 .

R 소스 코드 구성 에서와 같이 패키지를 생성하라는 몇 가지 답변을받을 수 있다는 것을 알고 있습니다. 하지만 다른 곳에서 사용할 무언가를 만드는 것이 아니라 독립형 프로젝트 일뿐입니다.



답변

가능한 한 가지 방법이 있습니다. exists함수를 사용 하여 util.R코드 에서 고유 한 것을 확인하십시오 .

예를 들면 :

if(!exists("foo", mode="function")) source("util.R")

( mode="function"Gavin Simpson이 지적한대로 를 포함하도록 편집 됨 )


답변

R은 호출을 추적하지 않고 source어디에서로드되었는지 파악할 수 없기 때문에 내장 된 그런 것은 없습니다 (패키지를 사용할 때는 해당되지 않습니다). 그러나 C .h파일 에서와 동일한 아이디어를 사용할 수 있습니다 . 즉, 전체를 다음으로 래핑합니다.

if(!exists('util_R')){
 util_R<-T

 #Code

}


답변

Say util.R는 함수를 생성합니다 foo(). 이 함수가 전역 환경에서 사용 가능한지 확인하고 그렇지 않은 경우 스크립트를 소싱 할 수 있습니다.

if(identical(length(ls(pattern = "^foo$")), 0))
    source("util.R")

이름을 가진 모든 것을 찾을 수 foo있습니다. 함수를 찾고 싶다면 (@Andrie exists()가 언급했듯이) 도움이되지만 찾을 객체의 유형을 정확히 알아야합니다.

if(exists("foo", mode = "function"))
    source("util.R")

다음은 exists()실행 중입니다.

> exists("foo", mode = "function")
[1] FALSE
> foo <- function(x) x
> exists("foo", mode = "function")
[1] TRUE
> rm(foo)
> foo <- 1:10
> exists("foo", mode = "function")
[1] FALSE


답변

파일 이름과 환경 이름을 사용하는 함수를 작성하고 파일이 환경에로드되었는지 확인하고 sys.source그렇지 않은 경우 파일을 소싱하는 데 사용 합니다.

다음은 빠르고 테스트되지 않은 기능입니다 (개선을 환영합니다!).

include <- function(file, env) {
  # ensure file and env are provided
  if(missing(file) || missing(env))
    stop("'file' and 'env' must be provided")
  # ensure env is character
  if(!is.character(file) || !is.character(env))
    stop("'file' and 'env' must be a character")

  # see if env is attached to the search path
  if(env %in% search()) {
    ENV <- get(env)
    files <- get(".files",ENV)
    # if the file hasn't been loaded
    if(!(file %in% files)) {
      sys.source(file, ENV)                        # load the file
      assign(".files", c(file, files), envir=ENV)  # set the flag
    }
  } else {
    ENV <- attach(NULL, name=env)      # create/attach new environment
    sys.source(file, ENV)              # load the file
    assign(".files", file, envir=ENV)  # set the flag
  }
}


답변

여기 내가 작성한 함수가 있습니다. base::source라는 전역 환경 목록에 소스 파일 목록을 저장하는 함수를 래핑합니다 sourced. 소스 .force=TRUE호출에 인수를 제공하는 경우에만 파일 을 리소스합니다. 인수 서명은 그렇지 않으면 실제와 동일 source()하므로 이것을 사용하기 위해 스크립트를 다시 작성할 필요가 없습니다.

warning("overriding source with my own function FYI")
source <- function(path, .force=FALSE, ...) {
  library(tools)
  path <- tryCatch(normalizePath(path), error=function(e) path)
  m<-md5sum(path)

  go<-TRUE
  if (!is.vector(.GlobalEnv$sourced)) {
    .GlobalEnv$sourced <- list()
  }
  if(! is.null(.GlobalEnv$sourced[[path]])) {
    if(m == .GlobalEnv$sourced[[path]]) {
      message(sprintf("Not re-sourcing %s. Override with:\n  source('%s', .force=TRUE)", path, path))
      go<-FALSE
    }
    else {
      message(sprintf('re-sourcing %s as it has changed from: %s to: %s', path, .GlobalEnv$sourced[[path]], m))
      go<-TRUE
    }
  }
  if(.force) {
    go<-TRUE
    message("  ...forcing.")
  }
  if(go) {
    message(sprintf("sourcing %s", path))
    .GlobalEnv$sourced[path] <- m
    base::source(path, ...)
  }
}

꽤 수다 스럽기 때문에 (에 대한 많은 전화 message()) 관심이 있다면 그 라인을 제거 할 수 있습니다. 베테랑 R 사용자의 조언을 주시면 감사하겠습니다. 저는 R을 처음 접했습니다.


답변

내 코드가있는 전체 주소를 사용하여 문제를 해결했습니다. 이전 :

if(!exists("foo", mode="function")) source("utils.r")

후:

if(!exists("foo", mode="function")) source("C:/tests/utils.r")


답변