如何将单个数字乘以 data.table 中的混合格式列

How to multiply a single number by a mixed format column in data.table

我有以下 data.table,我希望将 a 列乘以 b 列,a 总是一个数字,b 列有时可能是一个向量:

library(data.table)
tt <- c(33,44)
dt <- data.table(a=list(1,2,3)
                 , b = list(11,22,tt))

dt[, t2 := sapply(b, function(x) x*a)] 

我得到一个错误:Error in x * a : non-numeric argument to binary operator

因为 a 始终是单个数字,所以我预计第 3 行会起作用,即使 b 是一个向量。

我找到的解决方案是使用mapply:

dt[, t2 := mapply(function(x,y) x*y, a, b)]

为什么它不适用于 sapply/lapply?

dt$a[[1]] * dt$b有效吗? (不。)虽然第一个参数是长度为 1 的向量,但第二个参数不是向量,它是 list,并且 list 不进行算术运算。 sapply 仅迭代一个 list/vector 值,因此虽然 sapply(a, function(AA) AA * b) 似乎是一个好的开始,但 b 仍然反映出 list 因此无法完成。

您要做的是将 a[[1]] 乘以 b[[1]],然后将 a[[2]] 乘以 b[[2]],等等。这就是 Mapmapply好好干。

关于它们之间关系的一些事情。

## equivalent
lapply(lst1, function(z) z + 1)
Map(function(z) z + 1, lst1)

## equivalent
sapply(lst1, function(z) z + 1)
mapply(function(z) z + 1, lst1)

这就是单向量处理。但是当你想同时迭代多个(两个或更多)vectors/lists,将它们“压缩”在一起时,有两种选择:

stopifnot(length(lst1) == length(lst2))

## equivalent
sapply(seq_along(lst1), function(ind) {
  lst1[[ind]] * lst2[[ind]]
})
mapply(function(o1, o2) o1 * o2, lst1, lst2)
mapply(`*`, lst1, lst2)

了解它们的共性和差异:

  • sapplymapply 将尽可能简化 return 值,因此他们可能 return 一个 vector(如果 return 值为 1)、matrix(如果 return 值为向量)或 list(如果任何长度与其他长度不同)。您可以 force a list with sapply(..., simplify=FALSE) and mapply(..., SIMPLIFY=FALSE) (case difference is important).
  • lapplyMap总是returnlists,不管以上条件;许多人发现这种输出一致性在编程意义上更 reliable/desirable(即 functions/packages)。
  • 如果 vector/list 被命名,
  • lapply 只会 return 一个命名的 list,否则它只能在位置上索引;如果输入已命名或输入为 character,所有其他人将自动命名 returned list。 (可能还有更多 rules/exceptions,但这是一个开始。)