我想在数据表中做一个看似简单的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)]
两者都不起作用。我认为第一个是接近的。我希望有人可以在我的逻辑中指出缺陷,而不会创建一个可重复的例子。
答案 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