Предположим, мы начинаем с кадра данных data
, показанного ниже, с кодом генерации сразу под ним:
> data
To A B C
1 A 1 3 5
2 B 2 4 6
3 C 4 5 7
4 Sum 7 12 18
library(dplyr)
data <-
data.frame(
To = c("A","B","C"),
A = c(1,2,4),
B = c(3,4,5),
C = c(5,6,7)
) %>%
bind_rows(summarise_all(., ~(if(is.numeric(.)) sum(.) else "Sum")))
Я запускал следующий фрагмент кода, чтобы изменить значения в фрейме данных, очень похожие на проценты (каждая ячейка рассчитывается как% от соответствующего столбца «Сумма»):
data %>% mutate(across(-1, ~ ./.[To == "Sum"]))
Предоставление правильного вывода:
> data
To A B C
1 A 0.1428571 0.2500000 0.2777778
2 B 0.2857143 0.3333333 0.3333333
3 C 0.5714286 0.4166667 0.3888889
4 Sum 1.0000000 1.0000000 1.0000000
Как заменить делитель [To == "Sum"]
в mutate(across...))
динамической (возможно, числовой) ссылкой на последнюю строку фрейма данных? В более полном коде это развертывается в фрейме данных динамически и реактивно расширяется/сокращается на основе пользовательского ввода в Shiny, а имена заголовков столбцов также изменяются динамически, поэтому фиксированная ссылка на имя заголовка «Кому» в этом примере не оптимальна.
Краткое объяснение тоже было бы полезно, так что мне не нужно постоянно приходить к корыту в поисках решений.
@SamR Более простой вариант janitor::adorn_totals(data)
Мы можем использовать функцию last
, чтобы вернуть последнее значение столбца. Кроме того, есть еще один вариант с nth
, где мы можем получить значение столбца на основе более общего индекса, т. е. nth(., 2)
возвращает второе значение.
library(dplyr)
data %>%
mutate(across(-1, ~ ./last(.)))
-выход
To A B C
1 A 0.1428571 0.2500000 0.2777778
2 B 0.2857143 0.3333333 0.3333333
3 C 0.5714286 0.4166667 0.3888889
4 Sum 1.0000000 1.0000000 1.0000000
Это было слишком просто для тебя, Акрун! Вы заслуживаете перерыва время от времени с такими младшими вопросами! Спасибо за объяснение. В ближайшее время мне нужно будет проработать некоторые вводные материалы для dplyr и data.table.
Слишком просто для мастера Акруна!
в Base R вы можете сделать что-то вроде:
addmargins(prop.table(as.matrix(data.frame(data, row.names = 1)),2),1)
A B C
A 0.1428571 0.2500000 0.2777778
B 0.2857143 0.3333333 0.3333333
C 0.5714286 0.4166667 0.3888889
Sum 1.0000000 1.0000000 1.0000000
Попробуйте это: это более или менее то, что уже представляет akrun:
library(dplyr)
data <-
data.frame(
To = c("A","B","C"),
A = c(1,2,4),
B = c(3,4,5),
C = c(5,6,7)
) %>%
mutate(across(-1, ~ ./sum(.))) %>%
bind_rows(summarise_all(., ~(if(is.numeric(.)) sum(.) else "Sum")))
To A B C
1 A 0.1428571 0.2500000 0.2777778
2 B 0.2857143 0.3333333 0.3333333
3 C 0.5714286 0.4166667 0.3888889
4 Sum 1.0000000 1.0000000 1.0000000
Ответ @akrun правильный, но в R не очень идиоматично иметь строку суммы во фрейме данных, поэтому в конечном итоге вы сделаете что-то немного неловкое. Было бы лучше просто иметь фрейм данных значений, создать отдельный фрейм данных сумм для использования в операциях, и если вам нужно представить их в таблице, то привязать их, но только для представления, а не для расчета.