#r #dplyr #rlang
#r #dplyr #rlang
Вопрос:
Некоторое время я пытался объединить mutate_at
с coalesce
в случае, когда имена столбцов генерируются динамически.
В моем примере всего пять столбцов, но в реальных данных их намного больше (и не все столбцы следует включать в coalesce
шаг).
Пример DF:
data_example <- data.frame(
aa = c(1, NA, NA),
bb = c(NA, NA, 2),
cc = c(6, 7, 8),
aa_extra = c(2, 2, NA),
bb_extra = c(1, 2, 3)
)
Ожидаемый результат:
aa bb cc aa_extra bb_extra
1 1 1 6 2 1
2 2 2 7 2 2
3 NA 2 8 NA 3
вывод в виде structure
:
structure(list(aa = c(1, 2, NA), bb = c(1, 2, 2), cc = c(6, 7,
8), aa_extra = c(2, 2, NA), bb_extra = c(1, 2, 3)), class = "data.frame", row.names = c(NA,
-3L))
Я пробовал что-то подобное, но безуспешно («Только строки могут быть преобразованы в символы»). Я хотел бы избежать создания дополнительных переменных, просто включить все в mutate_at
выражение, поскольку это часть более длинного dplyr «потока».
data_example %>%
dplyr::mutate_at(
gsub("_extra", "", grep("_extra$",
colnames(.),
perl = T,
value = T)),
dplyr::funs(
dplyr::coalesce(., !!! dplyr::sym(paste0(., "_extra")))
)
)
Я также пробовал это (ошибок нет, но значения для столбца bb
неверны):
data_example %>%
dplyr::mutate_at(
gsub("_extra", "", grep("_extra$",
colnames(.),
perl = T,
value = T)),
dplyr::funs(
dplyr::coalesce(., !!as.name(paste0(names(.), "_extra")))
)
)
Как получить имя обрабатываемого столбца и передать его coalesce
?
Ответ №1:
Мы можем split
преобразовать набор данных в list
набор данных.кадры после удаления подстроки имен столбцов ( "_extra"
), затем с помощью map
цикла через list
, coalesce
столбец, а затем bind
с помощью столбцов «_extra» в исходном наборе данных
library(tidyverse)
data_example %>%
split.default(str_remove(names(.), "_extra")) %>%
map_df(~ coalesce(!!! .x)) %>%
#or use
# map_df(reduce, coalesce) %>%
bind_cols(., select(data_example, ends_with("extra")))
# A tibble: 3 x 5
# aa bb cc aa_extra bb_extra
# <dbl> <dbl> <dbl> <dbl> <dbl>
#1 1 1 6 2 1
#2 2 2 7 2 2
#3 NA 2 8 NA 3
Ответ №2:
Думаю, теперь можно достичь желаемого результата, используя mutate across
data_example %>%
mutate(across(c(str_subset(names(.), "_extra") %>% str_remove("_extra")) ,
~ coalesce( ., get(str_c(cur_column(), "_extra")) )))
aa bb cc aa_extra bb_extra
1 1 1 6 2 1
2 2 2 7 2 2
3 NA 2 8 NA 3
Ответ №3:
Используя data.table
для melt
и dcast
поскольку я никогда не могу вспомнить, как spread
и gather
работают
library(data.table)
library(dplyr)
data_example %>%
mutate(row = row_number()) %>%
melt('row') %>%
group_by(g = sub('_*$', '', variable), row) %>%
mutate(value = reduce(value, coalesce)) %>%
dcast(row ~ variable) %>%
select(-row)
# aa bb cc aa_extra bb_extra
# 1 1 1 6 1 1
# 2 2 2 7 2 2
# 3 NA 2 8 NA 2