Использование setDT внутри функции

Я пишу функцию, которая, между прочим, принуждает ввод к таблице данных.

library(data.table)
df <- data.frame(id = 1:10)
f <- function(df){setDT(df)}
f(df)
df[, temp := 1]

Однако последняя команда выводит следующее предупреждение:

Предупреждающее сообщение: В [.data.table (df, := (temp, 1)): Недействительный .Internal.selfref обнаружены и исправлены, взяв копию целого таблицу, чтобы: = добавить новый столбец по ссылке. При более раннем point, эта таблица данных была скопирована R (или была создана вручную используя структуру() или аналогичную). Избегайте ключевых < -, имен < - и attr < - которые в R в настоящее время (и странно) может скопировать всю таблицу данных. Используйте set * вместо этого следует избегать копирования:? set,? setnames и? setattr. Также, в R <= v3.0.2, список (DT1, DT2) скопировал весь DT1 и DT2 (список R() используется для копирования названных объектов); обновите до R > v3.0.2, если это кусаться. Если это сообщение не помогает, сообщите в службу данных поэтому основная причина может быть исправлена.

Я использую v1.9.3 data.table и R 3.1.1. Означает ли это, что df копируется в какой-то момент? Как избежать этого предупреждения?

Изменить: Код setDT фактически использует NSE. Таким образом, это работает:

df1 <- data.frame(id = 1:10)
f <- function(df){eval(substitute(setDT(df)),parent.frame())}
f(df1)
df1[, temp := 1]

Кажется, я могу делать другие вещи с df внутри функции f, например

df1 <- data.frame(id = 1:10)
f <- function(df){
      eval(substitute(setDT(df)),parent.frame())
      df[, temp := 1]
      }
f(df1)

Правильно ли это сделать?

Ответы

Ответ 1

Отличный вопрос! Предупреждающее сообщение должно указывать:... и фиксироваться с помощью неглубокой копии всей таблицы... Будет исправлено это.

setDT выполняет две вещи:

  • установите класс data.table из data.frame/list
  • используйте alloc.col для перераспределения столбцов (так что := можно использовать напрямую)

И для второго шага требуется неглубокая копия, если вход уже не является data.table. И именно поэтому мы присваиваем значение обратно символу в этой среде (родительский кадр setDT). Но родительский кадр для setDT является вашей функцией f(). Поэтому setDT(df) внутри вашей функции прошел гладко, но df, который находится в глобальной среде, изменит класс, а не перераспределение (поскольку мелкая копия разорвала ссылку).

И на следующем шаге := обнаруживает, что и мелкие копии еще раз перераспределяют.

Идея заключается в том, чтобы использовать setDT для преобразования в data.tables перед тем, как предоставить ее функции. Но я хотел бы, чтобы эти случаи были разрешены (посмотрим).

Спасибо, куча!