Reputation: 369
library(data.table)
a <- data.table(p = seq(1, 5, 0.5), s = 1:9)
b <- data.table(p = c(2.0, 6, 3.5), s = c(4, 7, 0))
I have 2 dataframes, dataframe "a" is the basis, dataframe "b" contains updates. I need to make changes to the dataframe "a" using the following conditions:
result:
p s
1: 1.0 1
2: 1.5 2
3: 2.0 4
4: 2.5 4
5: 3.0 5
6: 4.0 7
7: 4.5 8
8: 5.0 9
9: 6.0 7
Upvotes: 3
Views: 55
Reputation: 26218
using coalesce
it will be easier
a %>%
full_join(b, by = "p") %>%
transmute(p, s = coalesce(s.y, s.x)) %>%
filter(s != 0)
p s
1: 1.0 1
2: 1.5 2
3: 2.0 4
4: 2.5 4
5: 3.0 5
6: 4.0 7
7: 4.5 8
8: 5.0 9
9: 6.0 7
Upvotes: 1
Reputation: 21908
I first used full_join so that we have all the rows of both data frames. In case s.x and s.y are not equal and s.y is not an NA value it replaces s.x even in case of zeros which are later deleted. If s.x is NA and s.y is not which means that the row id for s.y coming from data frame b does not exist in data a it again replaces it.
library(dplyr)
library(tidyr)
library(stringr)
a %>%
full_join(b, by = "p") %>%
mutate(s.x = ifelse(s.x != s.y & !is.na(s.y), s.y, s.x),
s.x = ifelse(is.na(s.x) & !is.na(s.y), s.y, s.x)) %>%
select(-s.y) %>%
filter(s.x != 0) %>%
rename_with(~ str_remove(., ".x"), ends_with(".x"))
p s
1: 1.0 1
2: 1.5 2
3: 2.0 4
4: 2.5 4
5: 3.0 5
6: 4.0 7
7: 4.5 8
8: 5.0 9
9: 6.0 7
Upvotes: 3
Reputation: 6628
Using dplyr
(question does not specify if data.table
syntax is necessary).
p
that need to be deleted.distinct()
to make sure all rows are unique.library(dplyr)
to_delete <-
filter(b, s == 0) %>%
pull(p)
bind_rows(a, b) %>%
filter(!p %in% to_delete) %>%
distinct(p, .keep_all = TRUE)
#> p s
#> 1: 1.0 1
#> 2: 1.5 2
#> 3: 2.0 3
#> 4: 2.5 4
#> 5: 3.0 5
#> 6: 4.0 7
#> 7: 4.5 8
#> 8: 5.0 9
#> 9: 6.0 7
Upvotes: 4
Reputation: 886948
Perhaps a join on
'p' (assuming they have the same precision of values) to update the 's' by the corresponding 's' from 'b' (i.s
), remove the rows where 's' is 0 and rbind
the rows of 'b' whose 'p' values are not in a's p
rbind(a[b, s := i.s, on = .(p)][s != 0], b[!p %in% a$p])
-output
# p s
#1: 1.0 1
#2: 1.5 2
#3: 2.0 4
#4: 2.5 4
#5: 3.0 5
#6: 4.0 7
#7: 4.5 8
#8: 5.0 9
#9: 6.0 7
Upvotes: 2