使用 dplyr 和 across 计算多个点积

Using dplyr and across to compute multiple dot products

提问人:JCWong 提问时间:11/15/2023 更新时间:11/15/2023 访问量:49

问:

我有一个采用以下形式的数据帧

set.seed(100)
n = 1000
data = data.frame(
  y1_a = rnorm(n),
  y1_b = abs(rnorm(n)),
  y2_a = rnorm(n),
  y2_b = abs(rnorm(n))
)

我想计算 y1_a * y1_b 的点积,以及 y2_a * y2_b。

我能够像这样计算元素明智的产品mutateacross

data %>%
  mutate(
    (across(ends_with("a"), .names = '{.col}_b_dp') * across(ends_with("b")))
  )

这将生成 2 个额外的列,分别称为“y1_a_b_dp”和“y2_a_b_dp”。但这些是元素乘积,而不是点积。因此,需要对这些列求和以产生点积。

但我很好奇,有没有办法使用带有 2 个引用的 summarise 来跨越

data %>%
  summarise(
    colSums(across(ends_with("a"), .names = '{.col}_b_dp') * across(ends_with("b")))
  )

这几乎有效。它将元素乘积计算为 2 列,然后执行 colSums 以计算 2 个点积。但是,发回 summarise 的返回值是一个包含 2 行的数据帧,dplyr 对此表示不满。我希望发送到 summarise 的返回值是 2 列,就像在手动构造 mutate 和 sum 中一样。这可能吗?

r dplyr

评论


答:

3赞 stefan 11/15/2023 #1

为了提高可读性,这里是一种使用方法和一个小的便利函数:reframe

library(dplyr, warn.conflicts = FALSE)

dp <- function(x, y) {
  data.frame(
    t(colSums(x * y))
  )
}

data %>%
  reframe(
    dp(
      across(ends_with("a"), .names = "{.col}_b_dp"),
      across(ends_with("b"))
    )
  )
#>   y1_a_b_dp y2_a_b_dp
#> 1  57.31544 -15.33576

评论

1赞 Maël 11/15/2023
我真的很喜欢这个辅助功能的使用。它使这个双重技巧更具可读性。+1!across
1赞 stefan 11/15/2023
谢谢@Maël。从你那里学到了这个技巧。它仍然让我感到惊讶的是它有效。:D
1赞 one 11/15/2023 #2

这是另一种方法:

data %>%
  reframe(
    across(ends_with("a"), ~sum(. * get(gsub("a","b",cur_column()))),.names = '{.col}_b_dp') )

  y1_a_b_dp y2_a_b_dp
1  57.31544 -15.33576