I have a large data.frame
structured like the following example 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
In the real dataset there is an additional dimension (time) and there are many more numerical columns. I would like to manipulate df
using the dplyr
package (because it seems fast at these kind of operations) in the following way.
I need to subtract the y
and z
values for x
equal to b1
for id == A
( row = 2
), to a3
for id == B
( row = 4
) and to a1
for id == C
( row = 6
) from the remaining y
and z
values of A
, B
and C
respectively.
delete the rows that have been subtracted.
The resulting data.frame would be
# 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
In the real data.frame
I have multiple numeric columns (which I didn't show for simplicity) so that these operations should be applied to all columns. Notice that the codes in x
must refer to the id
because different id
can have the same x
codes (for example A
and C
).
I found this possible solution:
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)
it seems to work. Better/faster ideas?
If you're open to a data.table
solution, this should be fast:
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
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.