Почему выполнение следующей функции не ограничивается ростом дополнительного объекта? - PullRequest
0 голосов
/ 03 июля 2018

Ниже у меня есть три функции, которые выполняют одну и ту же операцию - дублируют данный data.frame и rbind его себе (т.е. плохая практика выращивания объекта).

Первая функция, f1, копирует входной объект в новый объект, x, затем увеличивает этот объект и, наконец, заменяет входной объект.

Вторая функция, f2, копирует входной объект в новый объект, x, а затем увеличивает входной объект.

Третья функция, f3, только увеличивает входной объект.

Я бы ожидал, что f1 будет самым медленным, учитывая, что по существу требуется, чтобы распределение памяти было изменено как для df, так и для x. Наоборот, все 3 функции кажутся примерно эквивалентными по времени вычислений. Как я могу понять это поведение? Мой пример некорректен?

## Functions
# copy df, grow copy, replace df with copy
f1 <- function(df){
  x <- df
  x <- rbind(x, x)
  df <- x
  return(df)
}

# copy df, grow df
f2 <- function(df){
  x <- df
  df <- rbind(df, x)
  return(df)
}

# grow df
f3 <- function(df){
  df <- rbind(df, df)
  return(df)
}


## Benchmark
df <- rbind(iris)
res <- microbenchmark(f1(df), f2(df), f3(df), times=5000L)


## Print results:
print(res)

# Unit: microseconds
#   expr    min      lq     mean  median      uq       max neval
# f1(df) 255.66 263.591 292.6851 270.123 292.516  2693.291  5000
# f2(df) 255.66 263.591 302.5159 270.590 292.516 15460.876  5000
# f3(df) 255.66 263.591 299.6157 270.122 292.516  3613.758  5000


## Plot results:
boxplot(res)

enter image description here

1 Ответ

0 голосов
/ 03 июля 2018

R функции используют копирование при модификации. Поэтому, когда вы передаете df в качестве аргумента, если вы не измените его, он будет указывать на тот же объект, который вы передали (тот же адрес).

То же самое происходит, если вы назначаете один и тот же объект. Например, используя address <- function(x) cat(data.table::address(x), "\n"):

> x <- 1
> address(x)
0x58164b8 
> y <- x
> address(y)
0x58164b8 

Итак, теперь печать некоторых адресов в ваших функциях

## Functions
# copy df, grow copy, replace df with copy
f1 <- function(df){
  address(x <- df)
  address(x <- rbind(x, x))
  address(df <- x)
  return(df)
}

# copy df, grow df
f2 <- function(df){
  address(x <- df)
  address(df <- rbind(df, x))
  return(df)
}

Результат:

> df <- rbind(iris)
> address(df)
0x543e378 
> res1 <- f1(df)
0x543e378 
0x5d3bd08 
0x5d3bd08 
> res2 <- f2(df)
0x543e378 
0x5c89e40 

Итак, каждая из ваших функций создает только один новый объект, поэтому они имеют одинаковую площадь.

...