Reputation: 103
I have two data frames
df1:
Id Name Column3
3 name1 fdf
12 name343 dfd
32 name65 sis
45 name23 rir
16 name98 tit
df2: Name column updated with new names in this data frame. Update the same newnames in df1 data frame.
Id Name Column3
12 newName1 dfd
45 newName34 rir
16 newName111 tit
I want to replace the Name in df1 with newNames in df2 based on Id column.
Expected output:
Id Name Column3
3 name1 fdf
12 newName1 dfd
32 name65 sis
45 newName34 rir
16 newName111 tit
Upvotes: 0
Views: 758
Reputation: 11878
dplyr 1.0.0 added a new experimental function rows_update()
that does exactly that:
library(tidyverse)
df1 <- read_table("Id Name Column3
3 name1 fdf
12 name343 dfd
32 name65 sis
45 name23 rir
16 name98 tit")
df2 <- read_table("Id Name Column3
12 newName1 dfd
45 newName34 rir
16 newName111 tit")
df1 %>% rows_update(df2, by = "Id")
#> # A tibble: 5 x 3
#> Id Name Column3
#> <dbl> <chr> <chr>
#> 1 3 name1 fdf
#> 2 12 newName1 dfd
#> 3 32 name65 sis
#> 4 45 newName34 rir
#> 5 16 newName111 tit
Upvotes: 2
Reputation: 1495
I'd do something like this:
library(dplyr)
data <- data1 %>%
left_join(data2, by = "Id") %>%
mutate(Name = ifelse(is.na(Name.y), Name.x, Name.y),
Col3 = ifelse(is.na(Col3.y), Col3.x, Col3.y)) %>%
select(Id, Name, Col3)
Giving you the required result. You can use merge
and if else
from base as well.
Or you could do:
data <- bind_rows(data1, data2) %>%
group_by(Id) %>%
slice(n())
Both solutions are not robust wrt to the order in which you join or bind the data frames.
Upvotes: 0
Reputation: 388982
You can use match
:
df1$Name[match(df2$Id, df1$Id)] <- df2$Name
df1
# Id Name Column3
#1 3 name1 fdf
#2 12 newName1 dfd
#3 32 name65 sis
#4 45 newName34 rir
#5 16 newName111 tit
If all the values in df2
are not present in df1
in that case it would be safer to join and select values.
library(dplyr)
df1 %>%
left_join(df2, by = 'Id') %>%
mutate(Name = coalesce(Name.y, Name.x)) %>%
select(Id, Name, Column3 = Column3.x)
Upvotes: 0