r如何使用mapply与数据表

时间:2018-04-25 16:32:29

标签: r data.table mapply

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

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

我有一个数据表,其中包含一个名为GDPratio的列和一些名称相似的列 x.food1,x.food2等。我将这些列名称放入一个名为x with

的变量中
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 :(得分:2)

如果我们使用的是Map/mapply,请务必附上单一列&#39; GDPRatio&#39;在list中将{@ 1}}中的list列中的.SD个字段作为单个单元进行回收。

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

否则,该单元将是vector中的单个元素,并且会使用.SD的相应列进行回收,并导致length问题,如OP&#39}中所述。代码

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

警告信息:1:在mapply中(FUN = f,...,SIMPLIFY = FALSE):
  较长的参数不是较短的长度的倍数2:In   [.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))

答案 1 :(得分:1)

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

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

这相当于@ Frank的建议和@ 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