Элегантное назначение нескольких столбцов в data.table с помощью lapply ()

Я пытаюсь найти элегантный способ использования:= назначение заменить много столбцов одновременно вdata.table применяя общую функцию. Типичным использованием этого может быть применение строковой функции (например,gsub) ко всем символьным столбцам в таблице. Это не сложно продлитьdata.frame способ сделать это сdata.table, но я'Я ищу метод в соответствии сdata.table способ делать вещи.

Например:

library(data.table)

m 

Ответы на вопрос(3)

Это должно работать, если вы хотите обратиться к столбцам по имени строки:

n = paste0("V", 20:100)
dt[, (n) := lapply(n, function(x) {sqrt(get(x))})]

или же

dt[, (n) := lapply(n, function(x) {sqrt(dt[[x]])})]
 David Arenburg06 мая 2016 г., 00:43
Может быть, добавить.SDcols варианты, такие какdt[, (n) := lapply(.SD, sqrt), .SDcols = n]? Хм .. на секунду подумал, может быть, Саймон уже сделал нечто подобное уже.
 eddi07 окт. 2015 г., 07:24
@HywelMJ спасибо, исправлено
 Tao Hu06 июн. 2018 г., 17:35
Какие'значит это п вlapply(n, function(x) {sqrt(dt[[x]])})
 HywelMJ07 окт. 2015 г., 00:56
Дополнительный) необходим в последней строке:dt[, (n) := lapply(n, function(x) {sqrt(dt[[x]])})]

Это то, что вы ищите?

dt[ , names(dt)[20:100] :=lapply(.SD, function(x) sqrt(x) ) , .SDcols=20:100]

Я слышал, сказать, что с помощью.SD не настолько эффективен, потому что он делает копию таблицы заранее, но если ваша таблица неогромный (очевидно, чтоОтносительно в зависимости от спецификаций вашей системы) Я сомневаюсь, что это будет иметь большое значение.

 attitude_stool05 июн. 2013 г., 18:18
@ Фрэнк, я нене знаю оfor петля +set подход. Мне придется подумать об использовании этого в будущем.
 Simon O'Hanlon12 июн. 2013 г., 21:26
@attitude_stool читатьэтот комментарий авторомdata.table, Видимо этоидеальный использование.SD и для чего он был разработан.
 Frank05 июн. 2013 г., 17:54
 David Arenburg06 мая 2016 г., 11:33
Вы могли бы также сократить это простоdt[ , 20:100 := lapply(.SD, sqrt), .SDcols = 20:100]
 Simon O'Hanlon05 июн. 2013 г., 17:59
@Frank +1 за этот ответ, и у меня есть закладки для дальнейшего использования. Я бы недумаю использоватьfor Цикл здесь. Умная.
Решение Вопроса

Да ты'Право здесь под вопросом:

Я понимаю, что более эффективно перебирать вектор имен столбцов, используя:= назначить:

for (col in paste0("V", 20:100)) dt[, col := sqrt(dt[[col]]), with = FALSE]

В сторону: обратите внимание, что новый способ сделать это:

for (col in paste0("V", 20:100))
  dt[ , (col) := sqrt(dt[[col]])]

посколькуwith = FALSE WASN»Легко читать, относится ли оно к LHS или RHS:=, Конец в сторону.

Как вы знаете, этоЭто эффективно, потому что это делает каждый столбец один за другим, поэтому рабочая память требуется только для одного столбца за раз. Это может иметь значение между его работой и сбоем из-за страшной ошибки нехватки памяти.

Проблема сlapply на RHS:= является то, что RHS (lapply) оценивается первым; то есть результат для 80 столбцов создан. Тот'с 80 колонка 'ценность новой памяти, которая должна быть выделена и заполнена. Так что вам нужно 80 колонкаДля успешного выполнения этой операции требуется объем свободной оперативной памяти. Это использование ОЗУ доминирует над последующей мгновенной операцией присваивания (plonking) эти 80 новых столбцов в data.table 'Слоты указателя столбца.

Как указывал @Frank, если у вас много столбцов (скажем, 10 000 или более), то небольшие накладные расходы на отправку в[.data.table метод начинает складываться). Чтобы устранить те накладные расходы, которые естьdata.table::set который под?set описывается какLoopable» :=, Я используюfor цикл для этого типа операции. Это'Это самый быстрый способ и довольно легко писать и читать.

for (col in paste0("V", 20:100))
  set(dt, j = col, value = sqrt(dt[[col]]))

Хотя всего с 80 столбцами, этовряд ли имеет значение. (Обратите внимание, что это может быть более распространеннымset по большому количеству строк, чем по большому количеству столбцов.)set Безразлично»t решить проблему повторного обращения кdt Название символа, которое вы упомянули в вопросе:

Я нене нравится это, потому что я неt как ссылка на data.table в выражении j.

Согласовано. Так что лучшее, что я могу сделать, это вернуться к вашему циклу:= но использоватьget вместо.

for (col in paste0("V", 20:100))
  dt[, (col) := sqrt(get(col))]

Тем не менее, я боюсь, что с помощьюget вj нести накладные расходы. Бенчмаркинг сделан в# 1380, Кроме того, возможно, это сбивает с толку, чтобы использоватьget() на RHS, но не на LHS. Для решения этой проблемы мы могли бы засорять LHS и позволитьget() также,# 1381:

for (col in paste0("V", 20:100))
  dt[, get(col) := sqrt(get(col))]

Также возможноvalue изset может быть запущен в рамках,DT# 1382.

for (col in paste0("V", 20:100))
  set(dt, j = col, value = sqrt(get(col))
 Farrel24 июн. 2016 г., 02:18
Большое спасибо за то, что поставили круглые скобкиcol, Пока я не вспомнил этот трюк, я получал колонку под названием "Col».

Ваш ответ на вопрос