почему столбце выбор(ы) с данными.результаты таблицы в копию?


[.data.tableji

Похоже, что колонки опции(ы) из данных.таблица с результатами в копии базового вектора(ов). Я говорю об очень простой выбор столбца, по имени, нет выражения для вычисления в и нет ни одной строки, чтобы подмножество в . Еще более странно, столбец поднабор данных.появляется рамка, чтобы не делать никаких копий. Я использую данные.таблица данных версии.таблица 1.10.4. Простой пример с указанием реквизитов и показателей приводится ниже. Мои вопросы:

  • Am I doing something wrong?
  • Is this a bug or is this the intended behavior?
  • If this is intended, what is the best approach to subset a data.table by columns and avoid extra copy?
  • Целевое использование-дело касается больших наборов данных, что позволяет избежать дополнительных копий нужно (тем более, что основания R, кажется, уже поддерживают).

    library(data.table)set.seed(12345)cpp_dt <- data.table(a = runif(1e6), b = rnorm(1e6), c = runif(1e6))cols=c("a","c")## naive / data.frame style of column selection## leads to a copy of the column vectors in colssubset_cols_1=function(dt,cols){  return(dt[,cols,with=F])}## alternative syntax, still results in a copysubset_cols_2=function(dt,cols){  return(dt[,..cols])}## work-around that uses data.frame column selection,## appears to avoid the copysubset_cols_3=function(dt,cols){  setDF(dt)  subset=dt[,cols]  setDT(subset)  setDT(dt)  return(subset)}## another approach that makes a "shallow" copy of the data.table## then NULLs the not needed columns by reference## appears to also avoid the copysubset_cols_4=function(dt,cols){  subset=dt[TRUE]  other_cols=setdiff(names(subset),cols)  set(subset,j=other_cols,value=NULL)  return(subset)}subset_1=subset_cols_1(cpp_dt,cols)subset_2=subset_cols_2(cpp_dt,cols)subset_3=subset_cols_3(cpp_dt,cols)subset_4=subset_cols_4(cpp_dt,cols)

    Теперь давайте посмотрим на распределение памяти и сравнить с исходными данными.

    .Internal(inspect(cpp_dt)) # original data, keep an eye on 1st and 3d vector# @7fe8ba278800 19 VECSXP g1c7 [OBJ,MARK,NAM(2),ATT] (len=3, tl=1027)#   @10e2ce000 14 REALSXP g1c7 [MARK,NAM(2)] (len=1000000, tl=0) 0.720904,0.875773,0.760982,0.886125,0.456481,...#   @10f1a3000 14 REALSXP g1c7 [MARK,NAM(2)] (len=1000000, tl=0) -0.947317,-0.636669,0.167872,-0.206986,0.411445,...#   @10f945000 14 REALSXP g1c7 [MARK,NAM(2)] (len=1000000, tl=0) 0.717611,0.95416,0.191546,0.48525,0.539878,...# ATTRIB: [removed]
    [.data.table

    Используя метод подмножество столбцов:

    .Internal(inspect(subset_1)) # looks like data.table is making a copy# @7fe8b9f3b800 19 VECSXP g0c7 [OBJ,NAM(1),ATT] (len=2, tl=1026)#   @114cb0000 14 REALSXP g0c7 [MARK,NAM(2)] (len=1000000, tl=0) 0.720904,0.875773,0.760982,0.886125,0.456481,...#   @1121ca000 14 REALSXP g0c7 [NAM(2)] (len=1000000, tl=0) 0.717611,0.95416,0.191546,0.48525,0.539878,...# ATTRIB: [removed]
    [.data.table

    Другой синтаксис версия, которая до сих пор использует и еще делаю копию:

    .Internal(inspect(subset_2)) # same, still copy# @7fe8b6402600 19 VECSXP g0c7 [OBJ,NAM(1),ATT] (len=2, tl=1026)#   @115452000 14 REALSXP g0c7 [NAM(2)] (len=1000000, tl=0) 0.720904,0.875773,0.760982,0.886125,0.456481,...#   @1100e7000 14 REALSXP g0c7 [NAM(2)] (len=1000000, tl=0) 0.717611,0.95416,0.191546,0.48525,0.539878,...# ATTRIB: [removed]
    setDF[.data.framesetDTac

    Используя последовательность , следуют и . Слушай, векторы и больше не копируется! Представляется, что метод базового R является более эффективным / имеет меньший объем памяти?

    .Internal(inspect(subset_3)) # "[.data.frame" is not making a copy!!# @7fe8b633f400 19 VECSXP g0c7 [OBJ,NAM(2),ATT] (len=2, tl=1026)#   @10e2ce000 14 REALSXP g1c7 [MARK,NAM(2)] (len=1000000, tl=0) 0.720904,0.875773,0.760982,0.886125,0.456481,...#   @10f945000 14 REALSXP g1c7 [MARK,NAM(2)] (len=1000000, tl=0) 0.717611,0.95416,0.191546,0.48525,0.539878,...# ATTRIB: [removed]

    Другой подход состоит в том, чтобы сделать мелкую копию данных.таблице, то нуль все лишние столбцы со ссылкой на новые данные.таблица. Снова нет копии.

    .Internal(inspect(subset_4)) # 4th approach seems to also avoid the copy# @7fe8b924d800 19 VECSXP g0c7 [OBJ,NAM(2),ATT] (len=2, tl=1027)#   @10e2ce000 14 REALSXP g1c7 [MARK,NAM(2)] (len=1000000, tl=0) 0.720904,0.875773,0.760982,0.886125,0.456481,...#   @10f945000 14 REALSXP g1c7 [MARK,NAM(2)] (len=1000000, tl=0) 0.717611,0.95416,0.191546,0.48525,0.539878,...# ATTRIB: [removed]
    subset_cols_3

    Теперь давайте посмотрим на показатели этих четырех подходов. Это выглядит как "[.данных.рама" () является явным победителем.

    microbenchmark({subset_cols_1(cpp_dt,cols)},               {subset_cols_2(cpp_dt,cols)},               {subset_cols_3(cpp_dt,cols)},               {subset_cols_4(cpp_dt,cols)},               times=100)# Unit: microseconds#                                 expr      min        lq      mean   median        uq       max neval#  {     subset_cols_1(cpp_dt, cols) } 4772.092 5128.7395 8956.7398 7149.447 10189.397 53117.358   100#  {     subset_cols_2(cpp_dt, cols) } 4705.383 5107.1690 8977.1816 6680.666  9206.164 53523.191   100#  {     subset_cols_3(cpp_dt, cols) }  148.659  177.9595  285.4926  250.620   283.414  4422.968   100#  {     subset_cols_4(cpp_dt, cols) }  193.912  241.9010  531.8308  336.467   384.844 20061.864   100