Назначение нескольких столбцов в 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
аргумент. Это также работает, но медленнее. Как правило, если вы можете векторизовать, вы должны.