Как передать формулу в качестве аргумента функции в r? - PullRequest
0 голосов
/ 30 сентября 2018

Как передать формулу в качестве аргумента в R?

Приведенный ниже код работает для первых двух случаев, но когда я передаю формулу, я получаю ошибку: Error in model.frame.default(formula = formula, weights = weights, na.action = na.omit, : invalid type (closure) for variable '(weights)'

makeModel<-function(formula,weights) {
    m <- lm(formula, na.action = na.omit, weights = weights)
    return(m);
}
run<-function(t) {
    f<-formula(t$y~t$x+t$r)
    m <- lm(t$y~t$x+t$r, na.action = na.omit, weights = t$size)
    m <- lm(f, na.action = na.omit, weights = t$size)
    m <- makeModels(f,t$size)    
}
l<-20
x<-seq(0,1,1/l)
y<-sqrt(x)
r=round(runif(n=length(x),min=0,max=.8))
n<-1:(l+1)
size=n/sum(n)
t<-data.frame(x,y,r,n,size)
run(t)

edit 1: этот код:

makeModel<-function(formula,weights,t) {
    print(class(weights))
    m <- lm(formula, na.action = na.omit, weights = weights,data=t)
    return(m);
}
run<-function(t) {
    f<-formula(y~x+r)
    f <- as.formula("t$y~t$x+t$r")
    m <- lm(y~x+r, na.action = na.omit, weights = t$size,data=t)
    m <- lm(f, na.action = na.omit, weights = t$size,data=t)
    m <- makeModel(f,t$size,t)    
}

выдает:

Ошибка в model.frame.default (формула = формула, данные = t, веса = веса,:недопустимый тип (замыкание) для переменной '(weights)'

edit 2: works:

makeModel <- function(formula, data) {
    # size is looked in data first, which is why this works
    m <- lm(formula, na.action = na.omit, weights = size, data =  data) # works
    #m <- lm(formula, na.action = na.omit, weights = data$size, data =  data) # fails!
    return(m)
}

r странно!

Кто-нибудь знает, почему строка с:weights = data $ size не работает?

Редактировать 3: Got: weights = data $ size to work.

makeModel<-function(formula,w,data) {
    print(class(weights))
    m <- lm(formula, na.action = na.omit, weights = size, data =  data) # works
    m <- lm(formula, na.action = na.omit, weights = data$size, data =  data) #works
    m <- lm(formula, na.action = na.omit, weights = w,data=data) # fails
    return(m);
}
run<-function(data) {
    f<-formula(y~x+r)
    #f <- as.formula("t$y~t$x+t$r")
    m <- lm(y~x+r, na.action = na.omit, weights = data$size,data=data)
    m <- lm(f, na.action = na.omit, weights = data$size,data=data)
    m <- makeModel(f,data$size,data)    
}

Последний сбой с ошибкой: eval (дополнительные данные, данные,env): объект 'w' не найден

Ответы [ 2 ]

0 голосов
/ 30 сентября 2018

См. Примеры в ?as.formula.Вы не должны явно вызывать переменные из их имен.Формула должна быть абстрактной, и lm будет знать, какие переменные нужно извлечь из data, которые вы должны указать.

makeModels <- function(formula, data) {
  # size is looked in data first, which is why this works
  m <- lm(formula, na.action = na.omit, weights = size, data =  data)
  return(m)
}

run <- function(t) {
  f <- formula(y ~ x + r)
  m1 <- lm(formula = f, na.action = na.omit, weights = size, data = t)
  m2 <- makeModels(formula = f, data = t)
  return(list(m1, m2))
}

l<-20
x<-seq(0,1,1/l)
y<-sqrt(x)
r=round(runif(n = length(x), min = 0, max = 0.8))
n<-1:(l+1)
size=n/sum(n)
t<-data.frame(x,y,r,n,size)
run(t)

[[1]]

Call:
lm(formula = f, data = t, weights = t$size, na.action = na.omit)

Coefficients:
(Intercept)            x            r  
   0.327154     0.706553    -0.008167  


[[2]]

Call:
lm(formula = formula, data = data, weights = size, na.action = na.omit)

Coefficients:
(Intercept)            x            r  
   0.327154     0.706553    -0.008167  
0 голосов
/ 30 сентября 2018

Избегайте присвоения объекта с именем t, который совпадает с функцией транспонирования.Глядя на результаты трассировки

makeModel<-function(formula,weights) {
  m <- lm(formula, na.action = na.omit, weights = weights)
  return(m)
}
run<-function(x) {
  f<-formula(x$y~x$x+x$r)
  m <- lm(x$y~x$x+x$r, na.action = na.omit, weights = x$size)
  m <- lm(f, na.action = na.omit, weights = x$size)
  m <- makeModel(f,x$size)    
}
l<-20
x<-seq(0,1,1/l)
y<-sqrt(x)
r=round(runif(n=length(x),min=0,max=.8))
n<-1:(l+1)
size=n/sum(n)
x<-data.frame(x,y,r,n,size)
run(x)
#R Error in model.frame.default(formula = formula, weights = weights, na.action = na.omit,  : 
#R    invalid type (closure) for variable '(weights)'
traceback()
#R 7: model.frame.default(formula = formula, weights = weights, na.action = na.omit, 
#R                        drop.unused.levels = TRUE)
#R 6: stats::model.frame(formula = formula, weights = weights, na.action = na.omit, 
#R                       drop.unused.levels = TRUE)
#R 5: eval(mf, parent.frame())
#R 4: eval(mf, parent.frame())
#R 3: lm(formula, na.action = na.omit, weights = weights) at #3
#R 2: makeModel(f, x$size) at #5
#R 1: run(t)

Теперь debug(model.frame.default) показывает, что эта строка находится там, где идет ошибка из-за этих строк и этой строки .Причина в том, что он вызывает

eval(list(weights = weights), environment(formula), environment(formula))

, и в среде run (среде, в которой назначена формула) не назначен объект weights, поэтому вместо него выдается stats::weights.Три решения:

makeModel <- function(formula, weights) {
  environment(formula) <- environment()
  lm(formula, na.action = na.omit, weights = weights)
}
run<-function(x) {
  f <- x$y ~ x$x + x$r
  makeModel(f, x$size)  
}
x1 <- run(x)

makeModel <- function(formula, weights) {
  cl <- match.call()
  cl[[1L]] <- quote(lm)
  cl$na.action <- quote(na.omit)
  eval(cl, parent.frame())
}
run<-function(x) {
  f <- x$y ~ x$x + x$r
  makeModel(f, x$size)  
}
x2 <- run(x)

makeModel <- function(formula, weights, x) {
  cl <- match.call()
  cl[[1]] <- quote(lm)
  cl$x <- NULL
  cl[c("data", "formula", "na.action")] <- 
    list(quote(x), formula, quote(na.omit))
  eval(cl)
}
run<-function(x) {
  f <- y ~ x + r
  makeModel(f, size, x)  
}
x3 <- run(x)

stopifnot(all.equal(coef(x1), coef(x2)))
stopifnot(all.equal(coef(x1), coef(x3), check.attributes = FALSE))

. В качестве примера, первое решение, приведенное выше, подразумевает, что

eval(list(weights = weights), environment(formula), environment(formula))

успешен, поскольку в среде formula назначен объект weights.Второе решение делает вызов в среде run с weights = x$size и, таким образом, успешно.Третий - как ответ Романа Луштрика , хотя его решение гораздо более чистое, чем третье, которое я предлагаю, если вы знаете, что аргумент weights всегда является столбцом size.Здесь вызывается

eval(list(weights = size), data, environment(formula))

, который работает, поскольку size является столбцом в data.

...