Является ли хорошей идеей присвоить NULL столбцу фрейма данных вместо поднабора? - PullRequest
0 голосов
/ 20 марта 2019

Предположим, у вас есть df:

df <- data.frame(A = 1 : 3, B = 2 : 4, C = 3 : 5, D = 4 : 6)

Теперь я хочу удалить столбец A из df, как меня учили использовать subset ting:

df <- df[, c("B", "C", "D")]
# or
df <- subset(df, select = -A)

Однако сегодня я узнал, что следующий код тоже может работать:

df$A = NULL

Что заставляет меня задать этот вопрос:

Это хорошая идея назначить NULL в столбец фрейма данных вместо поднабора?

Какая неявная разница (Ex семантика, производительность) между этими двумя, за исключением того, что subset возвращает новый объект?

1 Ответ

2 голосов
/ 20 марта 2019

Я пытался исследовать его с помощью tracemem, address и mem_change.

Различные методы:

#subset
my_df <- subset(my_df, select = -A)
# <- NULL
my_df$A <-  NULL
# set from data.table
set(my_df, j = "A", value = NULL)
# subset with []
my_df <- my_df[, colnames(my_df)[-1]]

Результаты:

method_name
<memory address from tracemem >
<address of df>
(Possibly tracemem results if object is copied)
memory change when column is deleted
<address of df after column deleted>
subset
[1] "<0x7f92c1504610>"
[1] "0x7f92c1504610"
-178 kB
[1] "0x7f92c1503a10"

имеет другой конечный адрес (ожидается при замене df)

<- NULL
[1] "<0x7f92c17b80e0>"
[1] "0x7f92c17b80e0"
tracemem[0x7f92c17b80e0 -> 0x7f92c1719a90]: eval eval mem_change 
tracemem[0x7f92c1719a90 -> 0x7f92c1746400]: $<-.data.frame $<- eval eval mem_change 
tracemem[0x7f92c1746400 -> 0x7f92c17006c0]: $<-.data.frame $<- eval eval mem_change 
-290 kB
[1] "0x7f92c17312e0"

<- NULL делает копию (tracemem results;несколько копий?), и конечный адрес отличается

set from data.table
[1] "<0x7f92c16227c0>"
[1] "0x7f92c16227c0"
-303 kB
[1] "0x7f92c16227c0"

набор имеет тот же конечный адрес.Даже если df не является data.table, data.table::set изменяет data.frames (и data.tables) по ссылке.

subset with []
[1] "<0x7f92c165cfa0>"
[1] "0x7f92c165cfa0"
-300 kB
[1] "0x7f92c161e950"

подмножество с [] также имеет другой конечный адрес

полный код:

.create_data <- function() {
  suppressWarnings(my_df <-
                     data.frame(matrix(rnorm(1000000),
                                       ncol = length(LETTERS))))
  colnames(my_df) <- copy(LETTERS)
  my_df
}

library(pryr)
library(data.table)

  ##### subset
  message("subset")
  my_df  <- .create_data()

  tracemem(my_df)
  address(my_df)

  mem_change(my_df <- subset(my_df, select = -A))

  address(my_df)
  untracemem(my_df)
  rm(my_df)
  invisible(gc())

  ##### <- NULL
  message("<- NULL")
  my_df <- .create_data()

  tracemem(my_df)
  address(my_df)

  mem_change(my_df$A <-  NULL)

  address(my_df)
  untracemem(my_df)
  rm(my_df)
  invisible(gc())

  ##### set from data.table
  message("set from data.table")
  my_df <- .create_data()

  tracemem(my_df)
  address(my_df)

  mem_change(set(my_df, j = "A", value = NULL))

  address(my_df)
  untracemem(my_df)
  rm(my_df)
  invisible(gc())

  ##### subset with []
  message("subset with []")
  my_df <- .create_data()

  tracemem(my_df)
  address(my_df)

  mem_change(my_df <- my_df[, colnames(my_df)[-1]])

  address(my_df)
  untracemem(my_df)
  rm(my_df)
  invisible(gc())
...