从 tibble (R, dplyr) 中的每一行中减去 1 行

Subtract 1 row from each row in a tibble (R, dplyr)

这应该很简单... dplyr 中的行向操作

#tibble
a=tibble(a=1:4,b=1:4,c=1:4)

#one row tibble to be subtracted from first one
b=tibble(a=5,b=5,c=5)

#well, this won't work
a-b

Error in Ops.data.frame(a, b) : 
  ‘-’ only defined for equally-sized data frames

当然,解决方法是复制 tibble 的行...但并不优雅

#replicating
c=tibble(a=rep(5,4),b=rep(5,4),c=rep(5,4))

#works
a-c

但这不应该与某些行操作一起使用吗?

a %>% rowwise %>% mutate(across(everything(), ~.-b))

没有

# A tibble: 4 × 3
# Rowwise: 
      a     b     c
  <int> <int> <int>
1     0     0     0
2     0     0     0
3     0     0     0
4     0     0     0

编辑:答案汇编

首先,更清晰地表述问题:

#tibble
a <- tibble(a=1:4,b=1:4,c=1:4)

#one row tibble to be subtracted from first one
b <- tibble(a=5,b=2,c=1)

#objective: turn this into a full-dplyr one-liner
a - b[rep(1,nrow(a)),]

现在,解决方案:

#Gregor's answer below is very clean
a %>% {. - b[rep(1, nrow(.)), ]}

#Full-dplyr is just slightly longer
a %>% {. - slice(b, rep(1,nrow(.)) ) }

#Ronak's answer is most compact
purrr::pmap_dfr(a, ~. - b)

#without the namespace even better:
pmap_dfr(a, ~. - b)

已编辑以反映 OP 的编辑...

我想这就是你想要的:

b=as.numeric(c(5,2,1))

#well, this works
a-b

> a-b
   a  b  c
1 -4 -4 -4
2 -3 -3 -3
3 -2 -2 -2
4 -1 -1 -1

当然

b=as.numeric(tibble(a=5,b=2,c=1))

有效。或者,如果您真的想将 b 保存为其他用途的 tibble...

b=tibble(a=5,b=2,c=1)
a-as.numeric(b)

也可以。请注意错误消息的文本: “Ops.data.frame(a, b) 中的错误: ‘-’仅为 equally-sized 数据帧定义”告诉你这一点。

如果您想留在 tidyverse 中,您可以使用 pmap_dfr,这将有助于对多列进行按行操作。

b=tibble(a=5,b=2,c=1)
purrr::pmap_dfr(a, ~. - b)

#   a  b c
#1 -4 -1 0
#2 -3  0 1
#3 -2  1 2
#4 -1  2 3

在基础 R 中,你可以做到

t(t(a) - unlist(b))

 #     a  b c
#[1,] -4 -1 0
#[2,] -3  0 1
#[3,] -2  1 2
#[4,] -1  2 3

请注意,为了清楚起见,我更改了 b 的值。

通常,使用 long-formatted 数据框可以使这些类型的操作保持一致。这里的技巧是创建一个行 ID,旋转更长,连接,然后旋转更宽。

library(tibble)

#tibble
a <- tibble(a=1:4,b=1:4,c=1:4)

#one row tibble to be subtracted from first one
b <- tibble(a=5,b=5,c=5)

library(tidyr)
library(dplyr)

a_pivot <- a |> 
  mutate(id = row_number()) |> # create a row ID so we can pivot_wider
  pivot_longer(cols = c(everything(), -id), values_to = "values_a")

b_pivot <- b |> 
  pivot_longer(cols = everything(), values_to = "values_b")

ab_pivot <- left_join(a_pivot, b_pivot, by = c("name")) |> 
  mutate(values = values_a - values_b) |> 
  select(id, name, values) |> # remove other columns for the pivot_wider
  pivot_wider(names_from = "name", values_from = values) |> 
  select(-id)

一个dplyr唯一的解决方案:

library(dplyr)

x = nrow(a)
b <- b %>% slice(rep(1:n(), each =x))

a - b
   a  b  c
1 -4 -4 -4
2 -3 -3 -3
3 -2 -2 -2
4 -1 -1 -1