Назначение нескольких столбцов в data.table() с условной функцией

В предыдущем вопросе Возвращение списка в dplyr mutate() было пояснено, что хотя dlpyr не может в выпуске 0.2 создать новые переменные из вектора, возвращаемого функцией, data.table() может использовать синтаксис -:

it[, c(paste0("V", 4:5)) := myfun(V2, V3)]

Если функция myfun из этого вопроса изменяется на:

myfun = function(arg1,arg2) {


if (arg1 > arg2) {
temp1 = arg1 + arg2
temp2 = arg1 - arg2 }
else {
temp1 = arg1 * arg2
temp2 = arg1 / arg2 }
list(temp1,temp2)

}

Приведенное выше решение возвращает предупреждение:

it = data.table(c("a","a","b","b","c"),c(1,2,3,4,5), c(2,3,4,2,2))
it[, c(paste0("V", 4:5)) := myfun(V2, V3)]

Warning message:
In if (arg1 > arg2) { :
  the condition has length > 1 and only the first element will be used

Это подразумевает, что каким-то образом data.table () передает функции более одной строки. Почему это происходит?

1 ответ

Решение

Рон, это ожидаемое поведение. data.table всегда проходит полные столбцы (если вы не используете by, в этом случае вы получаете часть столбца, которая соответствует каждой подгруппе). Чтобы обойти это, вам нужно векторизовать вашу функцию:

myfun2 = function(arg1,arg2) {
  temp1 <- ifelse(arg1 > arg2, arg1 + arg2, arg1 * arg2)
  temp2 <- ifelse(arg1 > arg2, arg1 - arg2, arg1 / arg2)
  list(temp1,temp2)
}

Я делаю это здесь, используя ifelse вместо if/else, Тогда это работает:

it = data.table(c("a","a","b","b","c"),c(1,2,3,4,5), c(2,3,4,2,2))
it[, c(paste0("V", 4:5)) := myfun2(V2, V3)]
it
#    V1 V2 V3 V4        V5
# 1:  a  1  2  2 0.5000000
# 2:  a  2  3  6 0.6666667
# 3:  b  3  4 12 0.7500000
# 4:  b  4  2  6 2.0000000
# 5:  c  5  2  7 3.0000000

Другой вариант, если вы не хотите изменять свою функцию, это разбить data.table в один ряд группы. Мы делаем это, передавая вектор by который имеет отдельное значение для каждой строки в data.table (чтобы каждая строка была группой):

it[, c(paste0("V", 4:5)) := myfun(V2, V3), by=1:nrow(it)]

Обратите внимание на by аргумент. Это также работает, но медленнее. Как правило, если вы можете векторизовать, вы должны.

Другие вопросы по тегам