首页 > 解决方案 > 在 R 中使用 dplyr 对 data.frame 进行快速操作

问题描述

我有一个大的data.frame结构,如下例df

df <- data.frame(id = c(rep("A",3), rep("B", 2), rep("C", 4)), 
                 x = c(paste0(letters[1:3],1) , paste0(letters[1:2],3), 
                       paste0(letters[1:4], 1)) , 
                 y = 1:9, z = 2:10 )
#   id  x y  z
# 1  A a1 1  2
# 2  A b1 2  3
# 3  A c1 3  4
# 4  B a3 4  5
# 5  B b3 5  6
# 6  C a1 6  7
# 7  C b1 7  8
# 8  C c1 8  9
# 9  C d1 9 10

在真实数据集中有一个额外的维度(时间),并且有更多的数字列。我想通过以下方式df使用dplyr包进行操作(因为这种操作看起来很快)。

  1. 我需要分别从,y和_ _ _ _ _ _ _ _ _ _ _ _zxb1id == Arow = 2a3id == Brow = 4a1id == Crow = 6yzABC

  2. 删除已减去的行。

结果 data.frame 将是

#   id  x y  z
# 1  A a1 -1 -1
# 2  A c1 1  1
# 3  B b3 1  1
# 4  C b1 1  1
# 5  C c1 2  2
# 6  C d1 3  3

实际上data.frame,我有多个数字列(为简单起见,我没有显示),因此这些操作应该应用于所有列。请注意,其中的代码x必须引用 ,id因为不同的代码id可以具有相同的x代码(例如AC)。

我找到了这个可能的解决方案:

df %>%
  mutate(cond = ifelse( (id == "A" & x == "b1") | ( id == "B" & x == "a3" ) | ( id == "C" & x == "a1" ) , 1, 0 ) ) %>%
  group_by(id) %>%
  mutate_at(vars("y", "z"),funs(.-.[cond==1])) %>%
  filter(cond == 0)

它似乎工作。更好/更快的想法?

标签: rfor-loopdplyr

解决方案


如果您愿意接受data.table解决方案,这应该很快:

library(data.table)
setDT(df)
keys <- data.table(id=c("A","B","C"), x=c("b1","a3","a1"))
onv <- c("id","x")
vars <- c("y","z")
df[df[keys, on=onv], on=onv[1], (vars) := .SD[,..vars] - mget(paste0("i.", vars))][!keys, on=onv]

#   id  x  y  z
#1:  A a1 -1 -1
#2:  A c1  1  1
#3:  B b3  1  1
#4:  C b1  1  1
#5:  C c1  2  2
#6:  C d1  3  3

推荐阅读