#r #dplyr #group-by #count #data-manipulation
#r #dplyr #группировать по #количество #манипулирование данными
Вопрос:
Учитывая таблицу, я пытаюсь научиться использовать R для суммирования переменных в зависимости от того, когда выполняется определенное условие (на основе других переменных в той же таблице).
Используя библиотеку dplyr (я создал некоторые данные), а затем суммировал данные по группам :
#load library
library(dplyr)
#create data
data <- data.frame(
"col_a" = c("aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa"),
"col_b" = c("123", "124", "125", "126", "127", "128", "129", "130"),
"col_c" = c("2015", "2015", "2015", "2015", "2015", "2015", "2015", "2015"),
"col_d" = c("red", "red", "red", "blue", "blue", "green", "green", "green"),
"day_a" = c("2001-01-01", "2000-01-05", "2000-01-01", "2010-12-20", "2010-12-20", "2020-05-05", "2020-05-05", "2020-05-28"),
"day_b" = c("2001-01-10", "2000-01-10", "2000-01-01", "2010-12-25", "2010-12-22", "2020-05-15", "2020-05-20", "2020-05-30")
)
#format variable types
data$col_a = as.factor(data$col_a)
data$col_b = as.factor(data$col_b)
data$col_c = as.factor(data$col_c)
#format date variables
data$day_a = as.factor(data$day_a)
data$day_b = as.factor(data$day_b)
data$day_1 = as.Date(as.character(data$day_a))
data$day_2 = as.Date(as.character(data$day_b))
#create new variable based on difference between date variables
data$diff = data$day_2 - data$day_1
data$diff = as.numeric(data$diff)
#create file that sums days based on groups of "col_a, col_c, col_d"
file = data%>%
group_by(col_a, col_c, col_d) %>%
dplyr::summarize(Total = sum(diff, na.rm=TRUE), Count = n())
file = as.data.frame(file)
Теперь, для групп «col_a, col_c, col_d», я хочу суммировать переменную «diff» на основе другого условия.
Например, для группы «aaa, 2015, зеленый» я хочу суммировать только «уникальные дни», то есть дни, которые перекрываются. (2020-05-05, 2020-05-15), ( 2020-05-05, 2020-05-20), (2020-05-28 ,2020-05-30)
Для этой группы мне нужно значение переменной «total» = 15 2 = 17 … вместо «27».
Это связано с тем, что даты (2020-05-05, 2020-05-15) полностью соответствуют датам (2020-05-05, 2020-05-20). Я хочу суммировать только «уникальные» периоды дат.
В итоге я пытаюсь получить что-то похожее на это:
final_result <- data.frame ( col_a = c("aaa", "aaa", "aaa"),
col_c = c("2015", "2015", "2015"),
col_d = c("blue", "green", "red"),
total = c("5","17","9"),
count = c("2", "3", "3")
)
Может кто-нибудь, пожалуйста, показать мне, как это сделать?
Спасибо
Комментарии:
1. Я считаю, что ваше ожидаемое значение для aaa / 2015 / red неверно, поскольку годы разные.
Ответ №1:
Вот подход с purrr::map2
:
Сначала преобразуйте Date
столбцы в целочисленные представления. Затем используйте map2
для создания векторов целочисленных последовательностей между двумя датами. Кажется, вы не хотите считать последний день, поэтому я вычел 1 из day 2
.
Теперь у нас есть новый столбец dates
, который содержит вектор дат в виде целых чисел.
library(purrr)
data %>%
transmute(dates = map2(as.integer(day_1),as.integer(day_2)-1,seq))
1 11323, 11324, 11325, 11326, 11327, 11328, 11329, 11330, 11331
2 10961, 10962, 10963, 10964, 10965
3 10957, 10956
4 14963, 14964, 14965, 14966, 14967
5 14963, 14964
6 18387, 18388, 18389, 18390, 18391, 18392, 18393, 18394, 18395, 18396
7 18387, 18388, 18389, 18390, 18391, 18392, 18393, 18394, 18395, 18396, 18397, 18398, 18399, 18400, 18401
8 18410, 18411
Затем мы можем сгруппировать, как вы делали ранее, и суммировать, не перечисляя даты для определенной группы и используя unique
для удаления дубликатов. Затем просто подсчитайте количество дат.
data %>%
mutate(dates = map2(as.integer(day_1),as.integer(day_2)-1,seq)) %>%
group_by(col_a, col_c, col_d) %>%
dplyr::summarize(Total = length(unique(unlist(dates))), Count = n())
# A tibble: 3 x 5
# Groups: col_a, col_c [1]
col_a col_c col_d Total Count
<fct> <fct> <chr> <int> <int>
1 aaa 2015 blue 5 2
2 aaa 2015 green 17 3
3 aaa 2015 red 16 3
Комментарии:
1. Спасибо за ваш ответ! Я думаю, это то, что я искал. После ввода следующей строки «data %>% transmute(dates = map2(as.integer(day_1),as.integer(day_2) -1, seq))» … отображается много чисел (например 11323, 11324, 11325, 11326, …). Что это за цифры?
2. Это только для демонстрационных целей, используйте второй код для достижения результатов.
3. Теперь я потрачу некоторое время, пытаясь изучить ваш ответ (который вы любезно предоставили), чтобы лучше понять логику. Я понимаю использование команд «mutate» и «group_by». Но как «length (unique (unlist (dates)))» гарантирует, что «даты учитываются только один раз»? Какова логика этого? Спасибо за всю вашу помощь.
4. Как вы можете видеть из верхней половины, мы создали вектор целых чисел, которые представляют каждый день между двумя датами. Представьте, что день 1
1
, день 22
и день 33
. Если мы представим два набора дат какlist(c(1,2),c(2,3))
, то, если мы оценимlength(unique(unlist(list(c(1,2),c(2,3)))))
, мы получим3
.