Как использовать mapply с таблицей данных - PullRequest
0 голосов
/ 25 апреля 2018

Я хочу сделать то, что кажется простым применением mapply в таблице данных. Я хочу умножить ряд столбцов таблицы данных на значение в другом столбце. Вот моя функция. y - это единственный столбец, на который умножаются значения в других столбцах. xIn - это имя столбца для выполнения этой операции.

f.xRatio <- function(xIn, y) {return(y * (xIn + 1)/(xIn - 1))}

У меня есть таблица данных со столбцом под названием GDPratio и некоторые столбцы с такими именами, как x.food1, x.food2 и т. д. Я помещаю имена этих столбцов в переменную с именем x, используя

x <- paste0("x.", foodNames)

Я создаю другую переменную с именами новых столбцов, созданных с помощью функции

xRatio <- paste0("xRatio.", foodNames)

Вот две версии моей попытки использовать mapply для создания столбцов xRatio из функции.

dt[, (xRatio) := mapply(FUN = f.xRatio, xIn = .SD, y = GDPRatio), .SDcols = (x)]

dt[, (xRatio) := mapply(FUN = f.xRatio, xIn = .(x), y = GDPRatio)]

Ни то, ни другое не работает. Я думаю, что первое близко. Я надеюсь, что кто-то может указать на недостатки в моей логике без создания воспроизводимого примера.

Ответы [ 2 ]

0 голосов
/ 25 апреля 2018

Подумайте, не применять цикл и использовать векторизованную арифметику для подмножества столбцов:

dt[, xRatio] <- dt$GDPRatio * (dt[, foodNames, with=FALSE]  + 1) / 
                              (dt[, foodNames, with=FALSE]  - 1)

Это будет эквивалентно предложению @ Фрэнка и ответу @ akrun с использованием следующих случайных данных:

foodNames <- c("apple", "banana", "orange")

set.seed(4252018)  # SEEDED FOR REPRODUCIBILITY

dt <- data.table(
  apple = abs(rnorm(50)) * 100,
  banana = abs(rnorm(50)) * 100,
  orange = abs(rnorm(50)) * 100,
  GDPRatio = abs(rnorm(50))
)

f.xRatio <- function(xIn, y) {return(y * (xIn + 1)/(xIn - 1))}
xRatio <- paste0("xRatio.", foodNames)

# @Parfait's NO LOOP FUNCTION
dt[, xRatio] <- dt$GDPRatio * (dt[, foodNames, with=FALSE]  + 1) / 
                              (dt[, foodNames, with=FALSE]  - 1)

# @Frank's COMMENT
frank_dt <- dt[, (xRatio) := lapply(.SD, f.xRatio, y = GDPRatio), .SDcols = xRatio]

all.equal(dt, frank_dt)
# [1] TRUE
identical(dt, newdt)
# [1] TRUE

# @akrun'S ANSWER
akrun_dt <- dt[, (xRatio) := Map(f.xRatio, .SD, list(GDPRatio)), .SDcols = xRatio]

all.equal(dt, akrun_dt)
# [1] TRUE
identical(dt, akrun_dt)
# [1] TRUE
0 голосов
/ 25 апреля 2018

Если мы используем Map/mapply, обязательно включите один столбец «GDPRatio» в list, чтобы принять его как единое целое, переработанное по list столбцов в .SD.

dt[, (xRatio) := Map(f.xRatio, .SD, list(GDPRatio)), .SDcols = x]

В противном случае блок будет vector единичным элементом, и он будет переработан с соответствующими столбцами .SD, что приведет к length проблемам, как указано в коде ОП

dt[, (xRatio) := Map(f.xRatio, .SD, GDPRatio), .SDcols = x]

Предупреждающие сообщения: 1: In mapply (FUN = f, ..., SIMPLIFY = FALSE):
более длинный аргумент не кратен длине более короткого 2: в [.data.table (dt,, := ((xRatio), Map (f.xRatio, .SD, GDPRatio)),: Прилагаются 2 столбца для назначения списка (длина 5) значений (3 не используется)

Данные

foodNames <- c("food1", "food2")
x <- paste0("x.", foodNames)
xRatio <- paste0("xRatio.", foodNames)

set.seed(24)
dt <- data.table(x.food1 = 2:6, x.food2 = 6:10, val = rnorm(5), 
                GDPRatio = c(0.5, 0.2, 0.3, 0.4, 0.1))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...