Существует dataframe ori_df, как его суммировать, чтобы избежать сообщения об ошибке или разумным способом? см. ниже отдельно вопрос 1 \ вопрос 2
ori_df <- data.frame(values = 1:10) %>% t() %>% as.data.frame()
colnames(ori_df) <- LETTERS[1:10]
map_list <- list('group_a' = c('A','D','E'),'group_b' = c('G','H','Z'))
вопрос 1: В Z
нет переменной ori_df
, как избежать ошибки и показать group_b
равным G
+ H
(Как исправить код ниже?)
group_df <- ori_df %>% mutate(group_a = A + D + E,
group_b = G + H + Z)
вопрос 2: Как создать переменные group_a
, group_b
в соответствии с map_list
и избежать ошибки, которой Z
нет в переменных ori_df
(Как исправить код ниже?)
group_df <- ori_df %>% rowwise() %>% mutate(sum=sum(c_across(map_list)))
@s_baldur Спасибо. Просто пример фрейма данных, в реальном мире много строк.
Для первого вопроса вы можете использовать функцию, которая проверяет, существует ли какой-либо элемент списка, а затем соответствующим образом удаляет его перед суммированием.
add <- function(...){
mc <- match.call(expand.dots = FALSE)$`...`
e <- sapply(mc, exists, where=ori_df)
sum(sapply(mc[e], eval, envir=ori_df), na.rm=TRUE)
}
А затем немного измените код:
ori_df %>% mutate(group_a = add(A, D, E),
group_b = add(G, H, Z))
A B C D E F G H I J group_a group_b
values 1 2 3 4 5 6 7 8 9 10 10 15
Для второго вопроса используйте any_of
:
mutate(ori_df,
group_a = sum(c_across(any_of(map_list$group_a))),
group_b = sum(c_across(any_of(map_list$group_b))))
A B C D E F G H I J group_a group_b
values 1 2 3 4 5 6 7 8 9 10 10 15
library(dplyr)
Я не уверен, что dplyr
— лучший способ. Используя базу R, вы просто перебираете map_list
для индексации целевых столбцов и объединяете результаты с исходными ori_df
.
cbind(ori_df, lapply(map_list, \(x) sum(ori_df[, colnames(ori_df) %in% x])))
A B C D E F G H I J group_a group_b
1 1 2 3 4 5 6 7 8 9 10 10 15
отличная работа, +1, и я думаю, вы можете использовать cbind(ori_df, lapply(map_list, \(x) sum(ori_df[, colnames(ori_df) %in% x])))
для более короткого кода или использовать list2DF
вместо as.data.frame
, чтобы немного его сократить
Можешь попробовать
cbind(
ori_df,
lapply(
map_list,
\(x) sum(t(ori_df)[match(x, names(ori_df)), ], na.rm = TRUE)
)
)
который дает
A B C D E F G H I J group_a group_b
values 1 2 3 4 5 6 7 8 9 10 10 15
Я бы использовал intersect():
foo_task1 <- function(df, group_list) {
df[names(group_list)] <- lapply(
group_list,
\(lst) rowSums(df[intersect(names(df), lst)])
)
df
}
foo_task1(ori_df, map_list)
# A B C D E F G H I J group_a group_b
# values 1 2 3 4 5 6 7 8 9 10 10 15
Ваш реальный data.frame также содержит только 1 строку?