根据匹配的值,覆盖数据框中特定的数值。

3

我的数据格式是这样的:

#>   country year value
#> 1     AUS 2019   100
#> 2     USA 2019   120
#> 3     AUS 2018    90

df <- data.frame(stringsAsFactors=FALSE,
     country = c("AUS", "USA", "AUS"),
        year = c(2019, 2019, 2018),
       value = c(100, 120, 90)
)

我有一个一行数据框,代表着一次修订,应该覆盖我的数据中现有的记录。

#>   country year value
#> 1     AUS 2019   500

df2 <- data.frame(stringsAsFactors=FALSE,
                  country = c("AUS"),
                     year = c(2018),
                    value = c(500)
             )

我的期望输出是:

#>   country year value
#> 1     AUS 2019   100
#> 2     USA 2019   120
#> 3     AUS 2018   500

我知道如何找到需要覆盖的行:

library(tidyverse)
df %>% filter(country == overwrite$country & year == overwrite$year) %>% 
  mutate(value = overwrite$value)

那我如何将它放回原始数据框中呢?

对我来说,使用Tidyverse的答案更容易处理,但我也可以接受其他解决方案。


1
来自@alistaire的相关博客文章。从这篇文章的评论中。在此帖子中的评论中。 - Andrew
3个回答

1

使用tidyverse的一种可能方法是:1)使用anti_joindf中删除将被替换的行,2)使用bind_rowsdf2添加替换行:

library(dplyr)

anti_join(df, df2, by = c("country", "year")) %>% bind_rows(df2)
#>   country year value
#> 1     AUS 2019   100
#> 2     USA 2019   120
#> 3     AUS 2018   500

或者,另一种方法是使用1)right_join连接旧值和新值,2)coalesce仅保留新值:

right_join(df2, df, by = c("country", "year")) %>%
    transmute(country, year, value = coalesce(value.x, value.y))
#>   country year value
#> 1     AUS 2019   100
#> 2     USA 2019   120
#> 3     AUS 2018   500

1
在这里,一种高效的方法是使用data.table进行连接。将"data.frame"转换为"data.table" (setDT(df)),在'country'、'year'上与'df2'连接(on), 将第二个数据集的'value'列(i.value)赋值(:=)替换原始数据集中的'value'。
library(data.table)
setDT(df)[df2, value := i.value, on = .(country, year)]
df
#    country year value
#1:     AUS 2019   100
#2:     USA 2019   120
#3:     AUS 2018   500

1
使用 mutateif_else
library(tidyverse)

df %>% 
mutate(value = if_else(country %in% df2$country & year %in% df2$year, df2$value, value))

结果为:

country year value
1     AUS 2019   100
2     USA 2019   120
3     AUS 2018   500


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接