2015-02-22 3 views
4

В книге расширенного R Hadley есть раздел об использовании сред в качестве «сосуда для больших объектов» (см. Ниже). Я ищу несколько примеров, иллюстрирующих лучшие практики для этого подхода. Я посмотрел here, но не нашел ничего, что бы явным образом рассматривало этот вопрос.Избегание копий с использованием сред

В случае, если это актуально, мое приложение является блестящим приложением, в котором данные в среде приложения совместно используются с экспортированными функциями (в R /). См. Также question.

Функция, используемая для управления потоком данных, - here. r_env - блестящая среда. Если функции анализа вызываются вне приложения, функция ищет данные, сбрасываемые в R (студия), когда пользователь выходит из приложения или в глобальной среде.

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

"Избежания копия Поскольку среды имеют эталонную семантику, вы никогда не будете случайно создать копию. Это делает его полезным сосудом для крупных объектов. Это общая методика Bioconductor пакетов, которые часто имеют управлять большими геномных объектов. "

EDIT

Я бы ожидать различия, основанные на том, как данные передаются функции. Используя несколько разных подходов, различия кажутся минимальными. Чем отличается подход, используемый в (неназванных) пакетах bioconductor, на которые ссылается Хэдли?

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

Вторая половина абзаца об исключении копий: «Изменения в R 3.1.0 сделали это использование существенно менее важным, поскольку изменение списка больше не делает глубокую копию. Ранее изменение одного элемента списка вызывало бы каждый элемент, который нужно скопировать, дорогостоящая операция, если некоторые элементы велики. Теперь изменение списка эффективно переводит существующие векторы, экономя много времени ». –

+0

В списках есть ссылочные семантики? Будет ли передача списков в функции для анализа такой же эффективной, как передача ссылки? Если это так, было бы здорово увидеть пример. – Vincent

+0

Если вы хотите узнать о R и производительности, я настоятельно рекомендую [this] (http://adv-r.had.co.nz/) книгу с открытым исходным кодом, в частности разделы [performance] (http: // adv -r.had.co.nz/Performance.html) и [память] (http://adv-r.had.co.nz/memory.html#memory) – Jthorpe

ответ

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 не изменился бы. Также, конечно, можно было бы ввести ссылочную семантику (исходная среда была бы изменена, даже если возвращаемое значение вызова функции было возвращено другому символу), что, вероятно, очень нежелательно.

Смежные вопросы