基于正则表达式合并数据框中的变量对

Ant*_*nce 8 r coalesce dataframe dplyr purrr

我想用来dplyr::coalesce查找包含多对变量的数据框中变量对之间的第一个非缺失值。目标是创建一个新的数据帧,现在每对变量只有一个副本(没有 NA 值的合并变量)。

这是一个例子:

df <- data.frame(
      A_1=c(NA, NA, 3, 4, 5),
      A_2=c(1, 2, NA, NA, NA),
      B_1=c(NA, NA, 13, 14, 15),
      B_2=c(11, 12, NA, NA, NA))


Expected output: 

A  B
1  11
2  12
3  13
4  14
5  15
Run Code Online (Sandbox Code Playgroud)

我猜测可以使用基于正则表达式的混合dplyr::coalescedplyr::mutate_at但我不知道该怎么做。有没有办法用 tidyverse 语法来完成这个任务?

谢谢!

编辑:感谢大家的回答!但是,我应该包含变量的命名约定,以便于将您的答案转移到我的实际问题上。对此我感到很抱歉。我的变量是地球化学变量,由两部分命名(化学元素名称加核心名称)。

示例:Al_TAC4.25.275其中Al是元素,TAC4.25.275是核心。我想为每个元素(名称的第一部分)合并来自 3 个不同核心(名称的第二部分)的数据。我有 25 对元素需要合并。

jar*_*rot 9

你可以使用transmute,例如

\n
library(dplyr)\n\ndf <- data.frame(\n  A_1 = c(NA, NA, 3, 4, 5),\n  A_2 = c(1, 2, NA, NA, NA),\n  B_1 = c(NA, NA, 13, 14, 15),\n  B_2 = c(11, 12, NA, NA, NA)\n  )\n\ndf %>%\n  transmute(A = coalesce(A_1, A_2),\n            B = coalesce(B_1, B_2))\n#>   A  B\n#> 1 1 11\n#> 2 2 12\n#> 3 3 13\n#> 4 4 14\n#> 5 5 15\n
Run Code Online (Sandbox Code Playgroud)\n

由reprex 包于 2021 年 12 月 22 日创建(v2.0.1)

\n

另一种选择,如果您有很多“A_*”和“B_*”列(来源:Romain Fran\xc3\xa7ois,用户:@Romain Francois):

\n
library(dplyr)\n\ndf <- data.frame(\n  A_1 = c(NA, NA, 3, 4, 5),\n  A_2 = c(1, 2, NA, NA, NA),\n  B_1 = c(NA, NA, 13, 14, 15),\n  B_2 = c(11, 12, NA, NA, NA)\n  )\n\ncoacross <- function(...) {\n  coalesce(!!!across(...))\n}\n\ndf %>%\n  transmute(A = coacross(starts_with("A_")),\n            B = coacross(starts_with("B_")))\n#>   A  B\n#> 1 1 11\n#> 2 2 12\n#> 3 3 13\n#> 4 4 14\n#> 5 5 15\n
Run Code Online (Sandbox Code Playgroud)\n

由reprex 包于 2021 年 12 月 22 日创建(v2.0.1)

\n

编辑

\n

根据您更新的问题,您没有大量的“A_*”或“B_*”列,而是大量的“*_1”、“*_2”和“*_3”列。我认为这是适合您的用例的最直接的解决方案:

\n
library(dplyr)\n\ndf <- data.frame(Al_TAC4.25.275 = c(1, 1, 1, NA, NA, NA),\n                 Al_TAC4.25.276 = c(NA, NA, 2, 2, 2, NA),\n                 Al_TAC4.25.277 = c(NA, NA, 3, NA, NA, 3),\n                 Au_TAC4.25.275 = c(1, 1, 1, NA, NA, NA),\n                 Au_TAC4.25.276 = c(NA, NA, 2, 2, 2, NA),\n                 Au_TAC4.25.277 = c(NA, NA, 3, NA, NA, NA),\n                 Ar_TAC4.25.275 = c(1, 1, 1, NA, NA, 1),\n                 Ar_TAC4.25.276 = c(NA, NA, 2, 2, 2, 2),\n                 Ar_TAC4.25.277 = c(NA, NA, 3, NA, NA, 3))\n\ndf\n#>   Al_TAC4.25.275 Al_TAC4.25.276 Al_TAC4.25.277 Au_TAC4.25.275 Au_TAC4.25.276\n#> 1              1             NA             NA              1             NA\n#> 2              1             NA             NA              1             NA\n#> 3              1              2              3              1              2\n#> 4             NA              2             NA             NA              2\n#> 5             NA              2             NA             NA              2\n#> 6             NA             NA              3             NA             NA\n#>   Au_TAC4.25.277 Ar_TAC4.25.275 Ar_TAC4.25.276 Ar_TAC4.25.277\n#> 1             NA              1             NA             NA\n#> 2             NA              1             NA             NA\n#> 3              3              1              2              3\n#> 4             NA             NA              2             NA\n#> 5             NA             NA              2             NA\n#> 6             NA              1              2              3\n\nnames(df) %>% \n  split(str_extract(., \'[:alpha:]+\')) %>%\n  map_dfc(~ coalesce(!!!df[.x][c(1,2,3)]))\n#> # A tibble: 6 \xc3\x97 3\n#>      Al    Ar    Au\n#>   <dbl> <dbl> <dbl>\n#> 1     1     1     1\n#> 2     1     1     1\n#> 3     1     1     1\n#> 4     2     2     2\n#> 5     2     2     2\n#> 6     3     1    NA\n\n# change the order of the list to change the \'priority\'\nnames(df) %>% \n  split(str_extract(., \'[:alpha:]+\')) %>%\n  map_dfc(~ coalesce(!!!df[.x][c(3,2,1)]))\n#> # A tibble: 6 \xc3\x97 3\n#>      Al    Ar    Au\n#>   <dbl> <dbl> <dbl>\n#> 1     1     1     1\n#> 2     1     1     1\n#> 3     3     3     3\n#> 4     2     2     2\n#> 5     2     2     2\n#> 6     3     3    NA\n\nnames(df) %>% \n  split(str_extract(., \'[:alpha:]+\')) %>%\n  map_dfc(~ coalesce(!!!df[.x][c(2,1,3)]))\n#> # A tibble: 6 \xc3\x97 3\n#>      Al    Ar    Au\n#>   <dbl> <dbl> <dbl>\n#> 1     1     1     1\n#> 2     1     1     1\n#> 3     2     2     2\n#> 4     2     2     2\n#> 5     2     2     2\n#> 6     3     2    NA\n
Run Code Online (Sandbox Code Playgroud)\n

由reprex 包于 2021 年 12 月 22 日创建(v2.0.1)

\n


Ano*_*n R 8

与我的另一个解决方案相比,这是另一个更简洁的解决方案。我认为使用cur_data()function 非常有帮助,但您也可以across(everything())在其位置使用:

library(dplyr)
library(purrr)

unique(sub("(\\D)_\\d+", "\\1", names(df))) %>%
  map_dfc(~ df %>%
            select(starts_with(.x)) %>%
             summarise(!!.x := do.call(coalesce, cur_data())))

  A  B
1 1 11
2 2 12
3 3 13
4 4 14
5 5 15
Run Code Online (Sandbox Code Playgroud)

这是针对尽可能多的对的另一种解决方案。请注意,我使用bang bang运算符 ( !!!) 来将数据帧的元素折叠为独立的单个参数,以便我可以应用coalesce它们:

library(dplyr)
library(rlang)

as.data.frame(do.call(cbind, lapply(split.default(df, sub("(\\D)_\\d+", "\\1", names(df))), function(x) {
  coalesce(!!!x)
})))

  A  B
1 1 11
2 2 12
3 3 13
4 4 14
5 5 15
Run Code Online (Sandbox Code Playgroud)

  • 很高兴在这里见到你! (3认同)
  • 兄弟永远是我的荣幸:) (2认同)

Tho*_*ing 5

基础 R 选项

list2DF(
  lapply(
    split.default(df, gsub("_.*", "", names(df))),
    rowSums,
    na.rm = TRUE
  )
)
Run Code Online (Sandbox Code Playgroud)

给出

  A  B
1 1 11
2 2 12
3 3 13
4 4 14
5 5 15
Run Code Online (Sandbox Code Playgroud)

  • 基R兄弟!你知道我迷恋“igraph”和网络分析。它完全改变了我对事物的看法:) (2认同)
  • @AnoushiravanR 很高兴听到这个消息。享受你的“igraph”之旅:) (2认同)