使用环境避免复制

时间:2015-02-22 07:55:12

标签: r shiny bioconductor

在哈德利的高级R书中,有一节将环境用作“大型物体的容器”(见下文施法)。我正在寻找一些例子来说明这种方法的最佳实践。我看了here,但没有找到任何明确解决这个问题的内容。

如果它是相关的,我的应用程序是一个闪亮的应用程序,其中应用程序环境中的数据与导出的函数(在R /中)共享。另请参阅此question

用于管理数据流的功能是herer_env是闪亮的环境。如果在应用程序外部调用分析函数,则该函数会在用户退出应用程序或全局环境时查找转储到R(studio)的数据。

http://adv-r.had.co.nz/Environments.html#explicit-envs

避免副本 由于环境具有引用语义,因此您永远不会意外地创建副本。这使它成为大型物体的有用容器。这是生物传导器包装的常用技术,通常必须管理大型基因组物体。 “

修改

我希望根据数据传递给函数的方式存在差异。使用几种不同的方法,差异似乎很小。 Hadley所指的(未命名的)生物传导器包的方法有何不同?

library(ggplot2)
library(microbenchmark)
dat <- diamonds
dataset <- "dat"
r_env <- new.env()
r_env$dat <- diamonds

reg1 <- function(dataset) 
    lm(price ~ carat + color, data = get(dataset))

reg2 <- function(dataset) 
    lm(price ~ carat + color, data = r_env[[dataset]])

reg3 <- function(dat) 
    lm(price ~ carat + color, data = dat)

microbenchmark(times = 100,
  reg1(dataset),
  reg2(dataset),
  reg3(dat)
)

Unit: milliseconds
          expr      min       lq     mean   median       uq      max neval
 reg1(dataset) 75.52479 85.50742 87.80560 87.57180 89.59216 96.34956   100
 reg2(dataset) 83.98896 85.51443 87.40334 87.00544 88.84889 94.01787   100
     reg3(dat) 61.00551 86.01789 88.15627 88.13501 90.48899 95.05454   100

1 个答案:

答案 0 :(得分:3)

对于列表和函数的参考语义,这是一个修改列表元素的函数

f = function (l) {
    l[[1]][1] = 2
    l
}

这是一个列表,它是应用函数之前和之后的内部表示

> l = list(a=1:5, b=1:5)
> .Internal(inspect(l))
@b3baa80 19 VECSXP g0c2 [NAM(1),ATT] (len=2, tl=0)
  @a4133a8 13 INTSXP g0c3 [] (len=5, tl=0) 1,2,3,4,5
  @a4133f0 13 INTSXP g0c3 [] (len=5, tl=0) 1,2,3,4,5
ATTRIB:
  @894b670 02 LISTSXP g0c0 [] 
    TAG: @1406d18 01 SYMSXP g1c0 [MARK,NAM(2),LCK,gp=0x6000] "names" (has value)
    @b3baab8 16 STRSXP g0c2 [] (len=2, tl=0)
      @15c8f68 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "a"
      @17f47e8 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "b"
> .Internal(inspect(f(l)))
@b2da518 19 VECSXP g0c2 [NAM(1),ATT] (len=2, tl=0)
  @6d6b3f0 14 REALSXP g0c4 [] (len=5, tl=0) 2,2,3,4,5
  @a4133f0 13 INTSXP g0c3 [NAM(2)] (len=5, tl=0) 1,2,3,4,5
ATTRIB:
  @85031c8 02 LISTSXP g0c0 [] 
    TAG: @1406d18 01 SYMSXP g1c0 [MARK,NAM(2),LCK,gp=0x6000] "names" (has value)
    @b3baab8 16 STRSXP g0c2 [NAM(2)] (len=2, tl=0)
      @15c8f68 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "a"
      @17f47e8 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "b"

在函数调用之前,这部分

@b3baa80 19 VECSXP g0c2 [NAM(1),ATT] (len=2, tl=0)
  @a4133a8 13 INTSXP g0c3 [] (len=5, tl=0) 1,2,3,4,5
  @a4133f0 13 INTSXP g0c3 [] (len=5, tl=0) 1,2,3,4,5

是列表(VECSXP)和整数向量(INTSXP)。 @是数据的内存地址。在函数调用之后我们有

@b2da518 19 VECSXP g0c2 [NAM(1),ATT] (len=2, tl=0)
  @6d6b3f0 14 REALSXP g0c4 [] (len=5, tl=0) 2,2,3,4,5
  @a4133f0 13 INTSXP g0c3 [NAM(2)] (len=5, tl=0) 1,2,3,4,5

整个列表的地址和修改后的元素的地址已经改变,但重要的是第二个元素的地址没有改变。

除了整体SXP不会改变外,人们会看到与环境类似的行为。当然也会引入引用语义(即使函数调用的返回值返回到不同的符号,原始环境也会改变),这可能是非常不合适的。