我想用于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
我猜可以使用基于正則運算式的dplyr::coalescewith混合,dplyr::mutate_at但我不知道該怎么做。有沒有辦法用tidyverse語法完成這個任務?
謝謝!
編輯:感謝大家的回答!但是,我應該為我的變數包含命名約定,以便于將您的答案轉移到我的實際問題中。我對此感到抱歉。我的變數是由兩部分命名的地球化學變數(化學元素名稱加上核心名稱)。
示例:Al_TAC4.25.275whereAl是元素,TAC4.25.275是核心。我想為每個元素(名稱的第一部分)合并來自 3 個不同核心(名稱的第二部分)的資料。我有 25 對元素要合并。
uj5u.com熱心網友回復:
你可以使用transmute,例如
library(dplyr)
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)
)
df %>%
transmute(A = coalesce(A_1, A_2),
B = coalesce(B_1, B_2))
#> A B
#> 1 1 11
#> 2 2 12
#> 3 3 13
#> 4 4 14
#> 5 5 15
由reprex 包(v2.0.1)于 2021 年 12 月 22 日創建
另一種選擇,如果您有很多“A_*”和“B_*”列(來源:Romain Fran?ois,用戶:@Romain Francois):
library(dplyr)
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)
)
coacross <- function(...) {
coalesce(!!!across(...))
}
df %>%
transmute(A = coacross(starts_with("A_")),
B = coacross(starts_with("B_")))
#> A B
#> 1 1 11
#> 2 2 12
#> 3 3 13
#> 4 4 14
#> 5 5 15
由reprex 包(v2.0.1)于 2021 年 12 月 22 日創建
編輯
根據您更新的問題,您沒有很多“A_*”或“B_*”列,而是有很多“*_1”、“*_2”和“*_3”列。我認為這是您的用例最直接的解決方案:
library(dplyr)
df <- data.frame(Al_TAC4.25.275 = c(1, 1, 1, NA, NA, NA),
Al_TAC4.25.276 = c(NA, NA, 2, 2, 2, NA),
Al_TAC4.25.277 = c(NA, NA, 3, NA, NA, 3),
Au_TAC4.25.275 = c(1, 1, 1, NA, NA, NA),
Au_TAC4.25.276 = c(NA, NA, 2, 2, 2, NA),
Au_TAC4.25.277 = c(NA, NA, 3, NA, NA, NA),
Ar_TAC4.25.275 = c(1, 1, 1, NA, NA, 1),
Ar_TAC4.25.276 = c(NA, NA, 2, 2, 2, 2),
Ar_TAC4.25.277 = c(NA, NA, 3, NA, NA, 3))
df
#> Al_TAC4.25.275 Al_TAC4.25.276 Al_TAC4.25.277 Au_TAC4.25.275 Au_TAC4.25.276
#> 1 1 NA NA 1 NA
#> 2 1 NA NA 1 NA
#> 3 1 2 3 1 2
#> 4 NA 2 NA NA 2
#> 5 NA 2 NA NA 2
#> 6 NA NA 3 NA NA
#> Au_TAC4.25.277 Ar_TAC4.25.275 Ar_TAC4.25.276 Ar_TAC4.25.277
#> 1 NA 1 NA NA
#> 2 NA 1 NA NA
#> 3 3 1 2 3
#> 4 NA NA 2 NA
#> 5 NA NA 2 NA
#> 6 NA 1 2 3
names(df) %>%
split(str_extract(., '[:alpha:] ')) %>%
map_dfc(~ coalesce(!!!df[.x][c(1,2,3)]))
#> # A tibble: 6 × 3
#> Al Ar Au
#> <dbl> <dbl> <dbl>
#> 1 1 1 1
#> 2 1 1 1
#> 3 1 1 1
#> 4 2 2 2
#> 5 2 2 2
#> 6 3 1 NA
# change the order of the list to change the 'priority'
names(df) %>%
split(str_extract(., '[:alpha:] ')) %>%
map_dfc(~ coalesce(!!!df[.x][c(3,2,1)]))
#> # A tibble: 6 × 3
#> Al Ar Au
#> <dbl> <dbl> <dbl>
#> 1 1 1 1
#> 2 1 1 1
#> 3 3 3 3
#> 4 2 2 2
#> 5 2 2 2
#> 6 3 3 NA
names(df) %>%
split(str_extract(., '[:alpha:] ')) %>%
map_dfc(~ coalesce(!!!df[.x][c(2,1,3)]))
#> # A tibble: 6 × 3
#> Al Ar Au
#> <dbl> <dbl> <dbl>
#> 1 1 1 1
#> 2 1 1 1
#> 3 2 2 2
#> 4 2 2 2
#> 5 2 2 2
#> 6 3 2 NA
由reprex 包(v2.0.1)于 2021 年 12 月 22 日創建
uj5u.com熱心網友回復:
與我的另一個解決方案相比,這是另一個更簡潔的解決方案。我認為在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
這是針對盡可能多的對的另一種解決方案。請注意,我使用 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
uj5u.com熱心網友回復:
基本 R 選項
list2DF(
lapply(
split.default(df, gsub("_.*", "", names(df))),
rowSums,
na.rm = TRUE
)
)
給
A B
1 1 11
2 2 12
3 3 13
4 4 14
5 5 15
uj5u.com熱心網友回復:
這是旋轉的替代方法:
library(dplyr)
library(tidyr)
df %>%
pivot_longer(
everything()
) %>%
mutate(name = substr(name, 1, 1)) %>%
na.omit %>%
pivot_wider(
names_from = name,
values_from = value,
values_fn = list
) %>%
unnest(cols = c(A, B))
A B
<dbl> <dbl>
1 1 11
2 2 12
3 3 13
4 4 14
5 5 15
uj5u.com熱心網友回復:
編輯:我相信這個解決方案即使在您編輯之后仍然有效。無論元素數量或每個元素的核心數量如何,它都可以作業。您只需要確保名稱一致,格式為"{element}_{core}".
library(tidyverse)
df %>%
mutate(id = 1:n()) %>%
pivot_longer(-id) %>%
filter(!is.na(value)) %>%
mutate(variable = str_extract(name, "^[^_] ")) %>%
group_by(id, variable) %>%
# Arrange by name (e.g. A_1) so that we could select the first non-NA
arrange(name) %>%
summarise(value = value[1]) %>%
pivot_wider(names_from = "variable")
輸出
# A tibble: 5 x 3
id A B
<int> <dbl> <dbl>
1 1 1 11
2 2 2 12
3 3 3 13
4 4 4 14
5 5 5 15
uj5u.com熱心網友回復:
我在這里要求它:https : //github.com/tidyverse/dplyr/issues/6109那里有一些可能的解決方案。例如
library(dplyr)
library(purrr)
df %>%
transmute(map2_dfc(.x = across(ends_with("_1"), .names = '{sub("_1","",.col)}'),
.y = across(ends_with("_2")),
.f = coalesce))
A B
1 1 11
2 2 12
3 3 13
4 4 14
5 5 15
或者也使用該功能
coalesce_prefix <- function(prefix) {
exprs <- map(prefix, function(p) {
expr(coalesce(
!!sym(paste0(p, ".x")),
!!sym(paste0(p, ".y"))
))
})
names(exprs) <- prefix
exprs
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/389578.html
下一篇:根據R中另一列的值計算一列的值
