Diğer betiklere (kaynak) R betiği nasıl eklenir


108

Projemdeki diğer betiklerden kullanmak istediğim bir yardımcı program R betiği (util.R) oluşturdum. Bu komut dosyasının tanımladığı işlevin diğer komut dosyalarımda da kullanılabilir olmasını sağlamanın doğru yolu nedir?

requireBir paketi yalnızca henüz yüklenmemişse yükleyen işleve benzer bir şey arıyorum . Aramak istemiyorum source("util.R")çünkü bu her çağrıldığında komut dosyasını yükleyecektir.

R Kaynak Kodunu Düzenlemede olduğu gibi bir paket oluşturmamı söyleyen bazı cevaplar alacağımı biliyorum :) Ama başka yerde kullanılacak bir şey yaratmıyorum, bu sadece bağımsız bir proje.


37
Her zaman bağımsız projeler için paketler oluşturuyorum. Çok fazla iş değil ve faydaları çok büyük. Devam et, bunu yapmak istediğini biliyorsun ...
Andrie

Yanıtlar:


93

İşte olası bir yol. Kodunuzda existsbenzersiz bir şey olup olmadığını kontrol etmek için işlevi kullanın util.R.

Örneğin:

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

( mode="function"Gavin Simpson'ın işaret ettiği gibi dahil edilecek şekilde düzenlendi )


4
Güzel kullanımı exists()- mode = "function"aptalca kanıtlamak için eklenmesi gerekiyor
Gavin Simpson

1
exists()R 3.0.2'de bir hata vermek dışında bir hata veriyor gibi görünüyor.
Michael Schubert

Doğru kullanım "var (" foo ") ve yanıt düzenlendi.
Andrie

18

Yerleşik böyle bir şey yoktur, çünkü R çağrıları takip etmez sourceve neyin nereden yüklendiğini anlayamaz (paketleri kullanırken durum böyle değildir). Yine de, C .hdosyalarında olduğu gibi aynı fikri kullanabilirsiniz , yani tamamını içine alın:

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

 #Code

}

ve sonra kod source("util.R")içinde arayın if, değil mi?
rafalotufo

1
@rafalotufo Her zamanki gibi kaynak ("util.R") yaparsınız. MBq yayınının kod gider içine util.R. Sadece yararlanılanın tüm gövdesini hemen şimdi dev bir if () ifadesine koyun, eğer mantıklıysa.
Keith Twombley

10

Say util.Rbir işlev üretir foo(). Bu işlevin global ortamda mevcut olup olmadığını kontrol edebilir ve değilse komut dosyasını kaynaklayabilirsiniz:

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

Bu adı taşıyan her şeyi bulacaktır foo. Bir işlev bulmak istiyorsanız, (@Andrie tarafından belirtildiği gibi) exists()yararlıdır, ancak tam olarak ne tür bir nesneyi arayacağınızın söylenmesi gerekir, ör.

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

İşte exists()eylemde:

> 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

Bu durumda, grepl(..., value=TRUE)arama teriminiz büyük olasılıkla bir normal ifade olmadığı için kullanmak isteyebilirsiniz . Bu arada +1.
Andrie

?? grepl()argüman yok value, ama muhtemelen regexp'i şurada düzeltmeliyim ls()...
Gavin Simpson

Üzgünüm, benim hatam. Demek istediğimfixed=TRUE
Andrie

@Andrie - Ah, tamam. Zaten işe yaramadı. Bunu düşünürken sürüklendim. exists()daha iyi ama şimdi görüyorum ki bu arada böyle bir Cevap göndermişsiniz.
Gavin Simpson

5

Bir dosya adı ve bir ortam adı alan, dosyanın ortama yüklenip yüklenmediğini kontrol eden ve yoksa dosyayı sys.sourcekaynak olarak kullanan bir işlev yazabilirsiniz .

İşte hızlı ve denenmemiş bir işlev (iyileştirmeler hoş geldiniz!):

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
  }
}

5

İşte yazdığım bir fonksiyon. base::sourceKaynaklı dosyaların bir listesini adlı global ortam listesinde depolamak için işlevi sarar sourced. Yalnızca kaynak .force=TRUEçağrısına bir argüman sağlarsanız bir dosyayı yeniden kaynaklayacaktır. Bağımsız değişken imzası aksi takdirde gerçekle aynıdır, bu source()nedenle bunu kullanmak için komut dosyalarınızı yeniden yazmanıza gerek yoktur.

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, ...)
  }
}

Oldukça konuşkan (çok sayıda arama message()), bu yüzden eğer umursuyorsanız bu hatları çıkarabilirsiniz. Deneyimli R kullanıcılarından gelen herhangi bir tavsiye takdir edilmektedir; R.'de oldukça yeniyim.


0

Kodumun olduğu adresin tamamını kullanarak sorunumu çözdüm: Daha önce:

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

Sonra:

if(!exists("foo", mode="function")) source("C:/tests/utils.r")
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.