在 R 中,当有多个列表需要匹配时,如何合并两个数据帧?

In R, how to combine two dataframes while there are multiple lists that need to be match?

20220418 次更新

我将我的数据框改得更像真实的

“NA”和“-3”表示缺失值


> dfA
# A tibble: 6 × 5
  city  name  bloodtype pulse20 pulse21
  <chr> <chr> <chr>       <dbl>   <dbl>
1 CityA Angel A              78      79
2 CityA Bob   B              90      91
3 CityB Cathy A              60      64
4 CityB Dean  B              70      71
5 CityC Ellen O              60      -3
6 CityC Faye  AB             75      -3


> dfB
# A tibble: 3 × 4
  city  name  bloodtype pulse21
  <chr> <chr> <chr>       <dbl>
1 CityC Ellen O              65
2 CityC Faye  AB             79
3 CityC Gaven O              68

我用join把它们合并成df_joined


library(dplyr)
df_joined <- 
  dfA %>% 
  full_join(dfB, by = c("city", "name"), suffix = c("", "_repla"))
df_joined
#”repla”stands for “replacement”

   > df_joined
# A tibble: 7 × 7
  city  name  bloodtype pulse20 pulse21 bloodtype_repla pulse21_repla
  <chr> <chr> <chr>       <dbl>   <dbl> <chr>                   <dbl>
1 CityA Angel A              78      79 NA                         NA
2 CityA Bob   B              90      91 NA                         NA
3 CityB Cathy A              60      64 NA                         NA
4 CityB Dean  B              70      71 NA                         NA
5 CityC Ellen O              60      -3 O                          65
6 CityC Faye  AB             75      -3 AB                         79
7 CityC Gaven NA             NA      NA O                          68

我可以一个一个地改变它们,但是有更多的“.repla”列,比如 100+

那么匹配相似列名并对其进行变异的有效方法是什么,例如,填充来自“formercolumnnames.repla”的所有新数据 到“以前的列名”

我查看了across()的帮助文档,但还是不太明白如何把它连接成一个清晰的方式。 谢谢你的帮助^^

20220417前题

我有2个数据框,

  1. dfA 是一个很大的数据集,包括所有城市和 2020-2021 年的所有健康数据,除了 c 市 2021 年的健康数据被标记为“-3”。

dfA


  1. dfB是一个很小的包含我要填入dfA的数据

dfB


请求: 1.how将这两个dataframe以通用的方式组合起来?

2.if 我使用“full_join”,Pulse21会被列为“Pulse21.x””Pulse21.y”,因此我需要做更多的绑定工作

3.For记录,在我的真实数据中, 每个城市有500多人, 并且健康数据会像 100 和更多。

  1. 那我还有什么办法可以让它更简单高效吗?非常感谢!
dplyr::rows_update(dfA, dfB, c('City', 'Name'))

   City  Name Pulse20 Pulse21
1 CityA   Amy      77      78
2 CityB   Bob      80      79
3 CityC Cathy      79      80

编辑:

对于您的新数据,您似乎在更新原始行的同时插入新行。您可以使用 row_upsertupdate + insert:

dplyr::rows_upsert(dfA, dfB, c('city', 'name'))

# A tibble: 7 x 5
  city  name  bloodtype pulse20 pulse21
* <chr> <chr> <chr>       <int>   <dbl>
1 CityA Angel A              78      79
2 CityA Bob   B              90      91
3 CityB Cathy A              60      64
4 CityB Dean  B              70      71
5 CityC Ellen O              60      65
6 CityC Faye  AB             75      79
7 CityC Gaven O              NA      68

有几种方法可以做到这一点。

其中大部分依赖于您首先将 -3 值更改为 NA 值,例如通过 mutate(across(where(is.numeric), ~ifelse(.x == -3, NA_real_, .x))).

下面是一些例子。

dplyr::rows_upsert

到目前为止,最简单的方法是使用 dplyr::rows_upsert() 旋转。这将使用 non-missing 数据更新缺失的行,并插入第一个 df 中不存在的行。

library(dplyr)

dfA %>% 
  mutate(across(where(is.numeric), ~ifelse(.x == -3, NA_real_, .x))) %>% 
  dplyr::rows_upsert(dfB, by = c("city", "name"))
#> # A tibble: 7 × 5
#>   city  name  bloodtype pulse20 pulse21
#>   <chr> <chr> <chr>       <dbl>   <dbl>
#> 1 CityA Angel A              78      79
#> 2 CityA Bob   B              90      91
#> 3 CityB Cathy A              60      64
#> 4 CityB Dean  B              70      71
#> 5 CityC Ellen O              60      65
#> 6 CityC Faye  AB             75      79
#> 7 CityC Gaven O              NA      68

reprex package (v2.0.1)

于 2022-04-18 创建

Note that this function is still experimental, and might change with future updates of dplyr.

full_join()pivot_longer()

如果我们先连接两个后缀不同的数据帧,我们可以让 tidyr::pivot_longer() 为我们合并它们。这将首先创建一个包含 dfAdfB 之间组合的长数据帧,但 na.omit() 确保我们只保留存在 none 个缺失值的值:

library(dplyr)

dfA %>% 
  full_join(dfB, by = c("city", "name"), suffix = c("_A", "_B")) %>% 
  mutate(across(where(is.numeric), ~ifelse(.x == -3, NA_real_, .x))) %>%
  tidyr::pivot_longer(
    ends_with(c("_A", "_B")), 
    names_to = ".value", 
    names_pattern = "(.*)_.*",
    values_drop_na = TRUE
  ) %>% 
  na.omit()
#> # A tibble: 6 × 5
#>   city  name  pulse20 bloodtype pulse21
#>   <chr> <chr>   <dbl> <chr>       <dbl>
#> 1 CityA Angel      78 A              79
#> 2 CityA Bob        90 B              91
#> 3 CityB Cathy      60 A              64
#> 4 CityB Dean       70 B              71
#> 5 CityC Ellen      60 O              65
#> 6 CityC Faye       75 AB             79

reprex package (v2.0.1)

于 2022-04-18 创建

Note that this solution removes the rows which only exists in dfB.

bind_rows()summarise()

首先使用bind_rows()我们可以按行组合两个df。通过对 id 列进行分组,我们可以使用例如median(na.rm = TRUE) 这将为我们删除缺失值:

library(dplyr)

dfA %>% 
  bind_rows(dfB) %>% 
  mutate(across(where(is.numeric), ~ifelse(.x == -3, NA_real_, .x))) %>% 
  group_by(city, name, bloodtype) %>% 
  summarise(
    across(
      everything(),
      ~median(.x, na.rm = TRUE)
    )
  ) %>% 
  ungroup()
#> `summarise()` has grouped output by 'city', 'name'. You can override using the
#> `.groups` argument.
#> # A tibble: 7 × 5
#>   city  name  bloodtype pulse20 pulse21
#>   <chr> <chr> <chr>       <dbl>   <dbl>
#> 1 CityA Angel A              78      79
#> 2 CityA Bob   B              90      91
#> 3 CityB Cathy A              60      64
#> 4 CityB Dean  B              70      71
#> 5 CityC Ellen O              60      65
#> 6 CityC Faye  AB             75      79
#> 7 CityC Gaven O              NA      68

reprex package (v2.0.1)

于 2022-04-18 创建

原回答

正如我原来的回答,您可以使用 full_join()mutate() 来修复 NA-3 问题。然而,当你有很多列时,这比上面提到的解决方案更难。

数据

dfA <- tibble::tribble(
  ~city,  ~name,  ~bloodtype, ~pulse20, ~pulse21,
  "CityA", "Angel", "A",              78,      79,
  "CityA", "Bob",   "B",              90,      91,
  "CityB", "Cathy", "A",              60,      64,
  "CityB", "Dean",  "B",              70,      71,
  "CityC", "Ellen", "O",              60,      -3,
  "CityC", "Faye",  "AB",             75,      -3
)

dfB <- tibble::tribble(
  ~city,  ~name,  ~bloodtype, ~pulse21,
  "CityC", "Ellen", "O",              65,
  "CityC", "Faye",  "AB",             79,
  "CityC", "Gaven", "O",              68
)