r 如何将 mapply 与数据一起使用 table

r how to use mapply with a data table

我想做一个看似简单的 mapply 在数据中的应用 table。我想将一系列数据 table 列乘以另一列中的值。这是我的功能。 y 是将其他列中的值乘以的单列。 xIn 是要执行此操作的列名。

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

我有一个数据 table,其中有一个名为 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)]

都不行。我认为第一个很接近。我希望有人可以指出我逻辑中的缺陷,而无需我创建可重现的示例。

如果我们使用 Map/mapply,请确保将单列 'GDPRatio' 括在 list 中,以将其作为在 list 中回收的单个单元.SD 中的列。

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

否则,该单元将是 vector 中的单个元素,并与 .SD 的相应列一起回收,并导致 length 问题,如 OP 代码中所述

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

Warning messages: 1: In mapply(FUN = f, ..., SIMPLIFY = FALSE) :
longer argument not a multiple of length of shorter 2: In [.data.table(dt, , :=((xRatio), Map(f.xRatio, .SD, GDPRatio)), : Supplied 2 columns to be assigned a list (length 5) of values (3 unused)

数据

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))

考虑不应用循环和运行跨列子集的矢量化算法:

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

这等同于@Frank 的建议和@ak运行 使用以下随机数据的回答:

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