【问题标题】:How to multiply a single number by a mixed format column in data.table如何将单个数字乘以 data.table 中的混合格式列
【发布时间】:2021-12-17 09:38:43
【问题描述】:

我有以下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?

【问题讨论】:

  • 'a' 和 'b' 都是列表。您想乘以列表列的相应元素。因此,可以使用Mapmapplysapply 您正在循环遍历单个列,并将“a”的整个列表与“b”的每个元素相乘。在第一个中,您正在做3 * list(1:3) Error in 3 * list(1:3) : non-numeric argument to binary operator
  • 同上...要清楚,dt[, t2 := Map(`*`, a, b)]

标签: r data.table


【解决方案1】:

dt$a[[1]] * dt$b 有效吗? (不。)虽然第一个参数是长度为 1 的向量,但第二个参数不是向量,它是 list,而 lists 不做算术。 sapply 仅迭代一个值列表/向量,因此虽然 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)

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

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 将尽可能简化返回值,因此它们可能会返回 vector(如果返回值为 1)、matrix(如果返回值是向量)或list(如果任何长度与其他长度不同)。您可以强制listsapply(..., simplify=FALSE)mapply(..., SIMPLIFY=FALSE) 结合使用(区分大小写很重要)。
  • lapplyMap 总是 返回lists,无论上述情况如何;许多人发现这种输出一致性在编程意义上(即在函数/包中)更可靠/更理想。
  • lapply 只会在向量/列表被命名时返回一个命名的list,否则它只能在位置上可索引;如果输入已命名或输入为character,则所有其他人将自动命名返回的list。 (可能有更多的规则/例外,但这是一个开始。)

【讨论】:

    猜你喜欢
    • 2021-10-24
    • 1970-01-01
    • 2017-03-11
    • 1970-01-01
    • 2017-12-15
    • 2012-09-19
    • 2023-02-20
    • 2016-05-12
    相关资源
    最近更新 更多