#r #tidyverse
#r #tidyverse
Вопрос:
Я хочу написать функцию, которая может агрегировать tibble путем объединения некоторых строк и столбцов. Вот небольшой пример (не как функция), который агрегирует столбцы A1 A3 и строки 1 и 3
A <- tibble(A = c("A1", "A2", "A3", "A4") ,
A1 = c(1,2,5,3),
A2 = c(2,4,2,5),
A3 = c(3,7,1,6),
A4 = c(1,3,2,4))
AGG <- A %>%
mutate(A1 = A1 A3) %>%
select(-A3)
AGG[1, 2:4] = AGG[1,2:4] AGG[3,2:4]
AGG <- AGG[c(1:2,4),]
Функция должна иметь в качестве аргументов номера столбцов (равные номерам строк). Для приведенного выше примера это будет:
AGG <- aggfunc(A, c(1,3))
Может быть простой способ, но все, что я могу найти до сих пор, — это довольно сложные решения, которые не работают.
Любая помощь приветствуется.
Приветствую Renger’а
Ответ №1:
Я считаю, что следующее делает то, что вы хотите. Поскольку он фильтрует индексы строк и столбцов, я выбрасываю столбец A
перед вызовом функции.
library(dplyr)
A <- tibble(A = c("A1", "A2", "A3", "A4") ,
A1 = c(1,2,5,3),
A2 = c(2,4,2,5),
A3 = c(3,7,1,6),
A4 = c(1,3,2,4))
aggfunc <- function(A, ind) {
target_col <- ind[1]
to_delete <- ind[-target_col]
AGG <- A
AGG[, target_col] <- rowSums(AGG[, ind])
AGG[target_col, ] <- as.list(colSums(AGG[ind, ]))
AGG[-to_delete, -to_delete]
}
aggfunc(select(A, -A), c(1,3))
что дает
# A tibble: 3 x 3
A1 A2 A4
<dbl> <dbl> <dbl>
1 10 4 3
2 9 4 3
3 9 5 4
Комментарии:
1. Работает идеально, также для более чем двух строк / столбцов!
Ответ №2:
Вот один из возможных dplyr
подходов. Предполагается, что ваш идентифицирующий столбец является первым столбцом data.frame
. Мы можем видеть, что для такого рода задач базовый R-подход намного проще.
library(dplyr)
# your data
A <- tibble(A = c("A1", "A2", "A3", "A4") ,
A1 = c(1,2,5,3),
A2 = c(2,4,2,5),
A3 = c(3,7,1,6),
A4 = c(1,3,2,4))
# the new function
aggfunc <- function(df, indices) {
new_colnm <- names(df)[indices[1] 1]
id_colnm = names(df)[1]
# add columns
temp <- df %>%
rowwise %>%
mutate(!! new_colnm := sum(c_across(indices 1))) %>%
select(!indices[-1] 1) %>%
ungroup
# add rows
temp %>%
rows_update(
tibble(!! id_colnm := new_colnm,
temp %>%
filter(row_number() %in% indices) %>%
summarise(across(indices[1] 1, sum))
)) %>%
slice(-indices[-1])
}
A %>%
aggfunc(c(1:3))
#> Matching, by = "A"
#> # A tibble: 2 x 3
#> A A1 A4
#> <chr> <dbl> <dbl>
#> 1 A1 27 1
#> 2 A4 14 4
Создано 2020-11-10 пакетом reprex (версия 0.3.0)
Комментарии:
1. Спасибо, он отлично работает для 2 строк / столбцов, но ваша функция работает только для агрегирования двух столбцов / строк, а не для большего количества (например, aggfun(A, c(1: 3)).
2. О, я понимаю. Как должен выглядеть результат, если имеется более двух столбцов?
3. например, c (1,3,4): все добавлено в первый столбец / строку. Итоговый tibble размером 2×3.
4. Я обновил свой ответ, теперь он должен работать с длиной векторов> 2.
Ответ №3:
Используя первый ответ (поскольку он позволяет выбирать более двух столбцов / строк для агрегирования, я немного скорректировал функцию, чтобы не потерять первый столбец:
aggfunc <- function(A, ind) {
target_col <- ind[1]
to_delete <- ind[-target_col]
newFirst <- A$A[-to_delete]
colnFirst <- colnames(A)[1]
AGG <- select(A, -A)
AGG[, target_col] <- rowSums(AGG[, find])
lastcol <- dim(AGG)[2]
AGG[target_col, ] <- as.list(colSums(AGG[ind,]))
AGG[-to_delete, -to_delete] %>%
add_column(newFirst, .before = .1) %>%
rename({{ colnFirst }} := newFirst)
}
Спасибо как Bas, так и TimTeaFan за их помощь. Я снова многому научился.