1

数式にいくつかの関数を含めることができるモデル構築関数があります。ユーザーが関数を複数回入力した場合に、最初の1回だけが警告とともに使用されるように機能させたいと思います。たとえば、lm同じ変数を2回使用すると、2番目の変数は削除されます。

y<-1:3
x<-1:3 
lm(y~x+x)

Call:
lm(formula = y ~ x + x)

Coefficients:
(Intercept)            x  
          0            1  

これは、でterms使用される関数model.frameが同じ名前の変数を削除するために機能します。しかし、私の場合、必ずしも同一の引数リストを持たない数式内の関数を使用しています。これらの関数の引数が重要にならないように、この動作を拡張したいと思います。

model(y~x+fn("x"))
  (Intercept) x temp
1           1 1    1
2           1 2    1
3           1 3    1
model(y~x+fn("x")+fn("x")) #identical function calls
  (Intercept) x temp
1           1 1    1
2           1 2    1
3           1 3    1
model(y~x+fn("x")+fn("z")) #function with different argument value
Error in attr(all_terms, "variables")[[1 + ind_fn]] : 
  subscript out of bounds

上記で使用した関数の例(非常に単純化されたもの)を次に示します。

model <- function(formula, data) {    

  #the beginning is pretty much copied from lm function    
  mf <- match.call(expand.dots = FALSE)   
  mf <- mf[c(1L,  match(c("formula", "data"), names(mf), 0L))]
  mf[[1L]] <- as.name("model.frame")
  mf$na.action <- as.name("na.pass")  

  all_terms <- if (missing(data)){ 
    terms(formula, "fn")
  } else terms(formula, "fn", data = data)

  #find the position of the function call in the formula
  ind_fn <- attr(all_terms, "specials")$fn

  #update the formula by removing the "fn" part
  if(!is.null(ind_fn)){
    fn_term <- attr(all_terms, "variables")[[1 + ind_fn]]
    formula <- update( formula, paste(". ~ .-", deparse(fn_term, 
                       width.cutoff = 500L, backtick = TRUE)))  
     mf$formula<-formula           
  } 

  # build y and X
  mf <- eval(mf, parent.frame())   
  y <- model.response(mf, "numeric")
  mt <- attr(mf, "terms")
  X <- model.matrix(mt, mf)


  #if fn was in formula do something with it
  if (!is.null(ind_fn)){

    foobar<-function(type=c("x","z")){
      if(type=="x"){
        rep(1,nrow(X))
      } else rep(0,nrow(X))
    }
    fn_term[[1]]<-as.name("foobar") 
    temp<-eval(fn_term)
    X<-cbind(X,temp)
  }  

  X
  }

スペシャル(関数呼び出し)の名前を確認して、最初の発生と同じ名前に変更することはできましたが、これに対処するためのより賢い方法があるかどうか疑問に思いました。

4

1 に答える 1