Поднабор в функции R второго уровня - PullRequest
4 голосов
/ 20 октября 2019

Функция foo1 может задавать список запрошенной переменной (например, by = type == 1). В противном случае foo1 просто выведет сам введенный список.

Для моих целей мне нужно использовать foo1 в новой функции под названием foo2.

В моем коде ниже: мой желаемый вывод получается примерно так: foo2(data = D, by = G[[1]]) ; foo2(data = D, by = G[[2]]) ; foo2(data = D, by = G[[3]]).

Но мне интересно, почему, когда я повторяю цикл G, используя lapply, я получаю ошибку как показано ниже ?

foo1 <- function(data, by){

  L <- split(data, data$study.name) ; L[[1]] <- NULL

  if(!missing(by)){

   L <- lapply(L, function(x) do.call("subset", list(x, by)))
  }
 return(L)
}


foo2 <- function(data, by){

  eval(substitute(foo1(data = data, by = by)))
}

## EXAMPLE OF USE:
D <- read.csv("https://raw.githubusercontent.com/izeh/i/master/k.csv", h = T) ## Data

G <- lapply(unique(na.omit(D$type)), function(i) bquote(type == .(i)))# all levels of `type`

foo2(data = D, by = G[[1]]) # Works fine without `lapply` :-)

lapply(1:3, function(i) foo2(data = D, by = G[[i]])) # Doesn't work with `lapply`! :-(
# Error in do.call("subset", list(x, by)) : object 'i' not found

Ответы [ 2 ]

2 голосов
/ 20 октября 2019

Вместо использования lapply, здесь можно использовать цикл for

lst1 <- vector("list", length(G))
for(i in 1:3) lst1[[i]] <- foo2(data = D, by = G[[i]])

-checking

identical(lst1[[2]],  foo2(data = D, by = G[[2]]))
#[1] TRUE
identical(lst1[[3]],  foo2(data = D, by = G[[3]]))
#[1] TRUE

Для части lapply, естьпохоже, конфликт с i анонимной функцией, которая также вызывается в G. Если мы используем новую переменную, скажем 'j'

lst2 <- lapply(1:3, function(j) foo1(data = D, by = G[[j]]))

должно работать

identical(lst2[[2]], lst1[[2]])
#[1] TRUE
1 голос
/ 20 октября 2019

Ваша foo2 функция пытается вычислить выражение

foo1(data = D, by = G[[i]])

, но не имеет i доступного. Вам нужно оценить G[[i]] в анонимной функции, которую вы передаете lapply, чтобы получить выражение, определяющее подмножество, а затем оценить это подмножество в foo2. Я рекомендую называть эту функцию вместо использования анонимной;это значительно облегчает отладку.

Вот некоторые перекодировки, которые работают:

Переопределение foo2 до

foo2 <- function(data, by){
  by <- eval(by, envir = data)
  foo1(data = data, by = by)
}

и

foo3 <- function(i) {
    expr <- G[[i]]
    foo2(data = D, by = expr)
}

а затем

lapply(1:3, foo3)

Я не уверен, что это именно то, что вы хотите, но оно должно быть достаточно близко, чтобы вы могли это исправить.

...