Список возврата против среды из функции R - PullRequest
0 голосов
/ 05 февраля 2019

Какие преимущества / недостатки есть в использовании одного над другим в следующих двух случаях?Case-I возвращает свои выходные данные как среду, а Case-II возвращает свои выходные данные в виде списка.

Case I:

function(x) {
  ret <- new.env()
  ret$x <- x
  ret$y <- x^2
  return(ret)
}

CaseII:

function(x) {
  ret <- list()
  ret$x <- x
  ret$y <- x^2
  return(ret)
}

1 Ответ

0 голосов
/ 05 февраля 2019

Хотя, похоже, есть различия в возврате списка и окружающей среды.От Advanced R :

Обычно среда похожа на список с четырьмя важными исключениями:

  • Каждое имя всреда уникальна.

  • Имена в среде не упорядочены (т. е. не имеет смысла спрашивать, что является первым элементом среды).

  • У среды есть родительский элемент.

  • В средах есть эталонная семантика.

Более технически среда составленаиз двух компонентов: фрейм, который содержит привязки объекта имени (и ведет себя так же, как именованный список), и родительская среда.К сожалению, «frame» используется в R. противоречиво. Например, parent.frame () не предоставляет вам родительский фрейм среды.Вместо этого он предоставляет вам среду вызова.Это обсуждается более подробно в вызывающих средах.

Из справки:

help(new.env)

Среды состоят из фрейма или набора именованных объектов и указателяв окружающую среду.Наиболее распространенным примером является кадр переменных, локальный для вызова функции;его вложением является среда, в которой была определена функция (если не было изменено впоследствии).Окружающая среда отличается от родительского фрейма: последний (возвращаемый parent.frame) относится к среде вызывающей функции.Поскольку путаница настолько проста, лучше никогда не использовать 'parent' в связи с окружением (несмотря на наличие функции parent.env).

из документации функции:

e1 <- new.env(parent = baseenv())  # this one has enclosure package:base.
e2 <- new.env(parent = e1)
assign("a", 3, envir = e1)
ls(e1)
#[1] "a"

Однако ls предоставит созданные среды:

ls()
#[1] "e1" "e2"

И вы можете получить доступ к своим объектам окружающей среды, как к списку:

e1$a
#[1] 3

Играя с вашими функциями:

f1 <- function(x) {
   ret <- new.env()
   ret$x <- x
   ret$y <- x^2
   return(ret)
}

res <- f1(2)
res
#<environment: 0x0000021d55a8a3e8>

res$y
#[1] 4

f2 <- function(x) {
   ret <- list()
   ret$x <- x
   ret$y <- x^2
   return(ret)

res2 <- f(2)
res2
#$x
#[1] 2

#$y
#[1] 4

res2$y
#[1] 4

Их производительность очень похожа, согласно microbenchmarking:

microbenchmark::microbenchmark(
   function(x) {
      ret <- new.env()
      ret$x <- x
      ret$y <- x^2
      return(ret)
   },
   function(x) {
      ret <- list()
      ret$x <- x
      ret$y <- x^2
      return(ret)
   },
   times = 500L
)

#Unit: nanoseconds
#                                                                                 #expr
# function(x) {     ret <- new.env()     ret$x <- x     ret$y <- x^2     #return(ret) }
#    function(x) {     ret <- list()     ret$x <- x     ret$y <- x^2     #return(ret) }
# min lq   mean median  uq  max neval
#   0  1 31.802      1 100  801   500
#   0  1 37.802      1 100 2902   500

, и они возвращают объекты с одинаковыми размерами:

object.size(res)
#464 bytes

object.size(res2)
#464 bytes

, и вы можетевсегда генерировать список из среды (list2env) и наоборот (as.list):

L <- list(a = 1, b = 2:4, p = pi, ff = gl(3, 4, labels = LETTERS[1:3]))
e <- list2env(L)
e$ff
# [1] A A A A B B B B C C C C
#Levels: A B C

as.list(e)
#$ff
# [1] A A A A B B B B C C C C
#Levels: A B C
#
#$p
#[1] 3.141593
#
#$b
#[1] 2 3 4
#
#$a
#[1] 1
...