Наверное, это Rdplyrsummarise вопрос.
У меня есть data.frame со значениями, записанными для субъектов с 5-минутными интервалами времени, и он имеет следующие три столбца: id: идентификатор субъекта, value: записанное значение в определенный момент времени и cum_time: совокупное значение времени для каждого id:
library(dplyr)
set.seed(1)
df <- data.frame(id = c(rep("id1", 100), rep("id2", 100), rep("id3", 100)),
value = runif (300, 10, 20)) %>%
dplyr::group_by(id) %>%
dplyr::mutate(cum_time = 5 * (dplyr::row_number()-1))
Я хотел бы вычислить data.frame с medians value за 60-минутные интервалы, чтобы получить такой результат data.frame:
rbind(data.frame(id = "id1", median_value = c(median(dplyr::filter(df, id == "id1" & cum_time >= 0 & cum_time <= 60)$value),
median(dplyr::filter(df, id == "id1" & cum_time >= 65 & cum_time <= 120)$value),
median(dplyr::filter(df, id == "id1" & cum_time >= 125 & cum_time <= 180)$value),
median(dplyr::filter(df, id == "id1" & cum_time >= 185 & cum_time <= 240)$value),
median(dplyr::filter(df, id == "id1" & cum_time >= 245 & cum_time <= 300)$value)),
cum_time = c(60, 120, 180, 240, 300)),
data.frame(id = "id2", median_value = c(median(dplyr::filter(df, id == "id2" & cum_time >= 0 & cum_time <= 60)$value),
median(dplyr::filter(df, id == "id2" & cum_time >= 65 & cum_time <= 120)$value),
median(dplyr::filter(df, id == "id2" & cum_time >= 125 & cum_time <= 180)$value),
median(dplyr::filter(df, id == "id2" & cum_time >= 185 & cum_time <= 240)$value),
median(dplyr::filter(df, id == "id2" & cum_time >= 245 & cum_time <= 300)$value)),
cum_time = c(60, 120, 180, 240, 300)),
data.frame(id = "id3", median_value = c(median(dplyr::filter(df, id == "id3" & cum_time >= 0 & cum_time <= 60)$value),
median(dplyr::filter(df, id == "id3" & cum_time >= 65 & cum_time <= 120)$value),
median(dplyr::filter(df, id == "id3" & cum_time >= 125 & cum_time <= 180)$value),
median(dplyr::filter(df, id == "id3" & cum_time >= 185 & cum_time <= 240)$value),
median(dplyr::filter(df, id == "id3" & cum_time >= 245 & cum_time <= 300)$value)),
cum_time = c(60, 120, 180, 240, 300)))
id median_value cum_time
1 id1 15.72853 60
2 id1 15.74687 120
3 id1 14.87811 180
4 id1 16.00048 240
5 id1 14.57858 300
6 id2 15.98761 60
7 id2 14.65317 120
8 id2 15.36035 180
9 id2 15.16835 240
10 id2 13.90954 300
11 id3 12.68951 60
12 id3 15.79852 120
13 id3 14.03968 180
14 id3 14.29187 240
15 id3 15.11250 300





Возможно, этот подход подойдет вам (с дополнением благодаря @thelatemail)?
df %>%
filter(cum_time<=300) %>%
group_by(id, grp=cut(cum_time, seq(0, max(cum_time),60), include.lowest = T)) %>%
summarize(median_value = median(value), cum_time=max(cum_time), .groups = "drop") %>%
select(-grp)
Выход:
id median_value cum_time
1 id1 15.72853 60
2 id1 15.74687 120
3 id1 14.87811 180
4 id1 16.00048 240
5 id1 14.57858 300
6 id2 15.98761 60
7 id2 14.65317 120
8 id2 15.36035 180
9 id2 15.16835 240
10 id2 13.90954 300
11 id3 12.68951 60
12 id3 15.79852 120
13 id3 14.03968 180
14 id3 14.29187 240
15 id3 15.11250 300
предоставленный интервал не является непрерывным. второй интервал начинается с 65, а не с 61. Я предлагаю добавить в интервал больше разрезов, а затем отфильтровать их перед суммированием.
Если вы добавите cum_time = max(cum_time) к вызову summarise, вы даже сможете пометить его по запросу.
Непоследовательные интервалы сложны; возможно, вы могли бы «разбить его на две части», а затем соединить результат? Например.
Пример данных:
library(dplyr)
library(RcppRoll)
set.seed(1)
df <- data.frame(id = c(rep("id1", 100), rep("id2", 100), rep("id3", 100)),
value = runif (300, 10, 20)) %>%
dplyr::group_by(id) %>%
dplyr::mutate(cum_time = 5 * (dplyr::row_number()-1))
expected_outcome <- rbind(data.frame(id = "id1", median_value = c(median(dplyr::filter(df, id == "id1" & cum_time >= 0 & cum_time <= 60)$value),
median(dplyr::filter(df, id == "id1" & cum_time >= 65 & cum_time <= 120)$value),
median(dplyr::filter(df, id == "id1" & cum_time >= 125 & cum_time <= 180)$value),
median(dplyr::filter(df, id == "id1" & cum_time >= 185 & cum_time <= 240)$value),
median(dplyr::filter(df, id == "id1" & cum_time >= 245 & cum_time <= 300)$value)),
cum_time = c(60, 120, 180, 240, 300)),
data.frame(id = "id2", median_value = c(median(dplyr::filter(df, id == "id2" & cum_time >= 0 & cum_time <= 60)$value),
median(dplyr::filter(df, id == "id2" & cum_time >= 65 & cum_time <= 120)$value),
median(dplyr::filter(df, id == "id2" & cum_time >= 125 & cum_time <= 180)$value),
median(dplyr::filter(df, id == "id2" & cum_time >= 185 & cum_time <= 240)$value),
median(dplyr::filter(df, id == "id2" & cum_time >= 245 & cum_time <= 300)$value)),
cum_time = c(60, 120, 180, 240, 300)),
data.frame(id = "id3", median_value = c(median(dplyr::filter(df, id == "id3" & cum_time >= 0 & cum_time <= 60)$value),
median(dplyr::filter(df, id == "id3" & cum_time >= 65 & cum_time <= 120)$value),
median(dplyr::filter(df, id == "id3" & cum_time >= 125 & cum_time <= 180)$value),
median(dplyr::filter(df, id == "id3" & cum_time >= 185 & cum_time <= 240)$value),
median(dplyr::filter(df, id == "id3" & cum_time >= 245 & cum_time <= 300)$value)),
cum_time = c(60, 120, 180, 240, 300)))
Пример кода:
first_block <- df %>%
filter(cum_time <= 60) %>%
mutate(median_value = median(value)) %>%
select(-value) %>%
filter(cum_time == 60)
second_time_block <- df %>%
filter(cum_time >= 65) %>%
mutate(median_value = roll_median(value, n = 12, by = 12, fill = NA,
align = c("right"))) %>%
select(-value) %>%
filter(cum_time %% 60 == 0)
outcome <- first_block %>%
bind_rows(second_time_block) %>%
arrange(cum_time, .by_group = TRUE) %>%
filter(cum_time <= 300)
all_equal(expected_outcome, outcome)
#> [1] TRUE
Created on 2024-05-17 with reprex v2.1.0
Желаемый интервал выглядит как (0-60,65-120,125-180,...) с пробелами.
Мы можем использовать cut() и, поскольку эта функция требует непрерывных интервалов без пробелов, потому что вы объявляете breaks интервалов в cut(). Поэтому нам просто нужно будет удалить интервалы, которые после этого не нужны.
foo = function(x){
cut(x,breaks=c(-1,60,64,120,124,180,184,240,244,300),
labels=c("60","remove","120","remove","180","remove","240","remove","300"))
}
df |>
mutate(cum_interval=foo(cum_time))|>
filter(cum_interval! = "remove") |>
group_by(id,cum_interval)|>
summarise(median_value=median(value))
Не совсем 60-минутный интервал, если мы начинаем с 65 во 2-м интервале. Если бы между интервалами не было промежутка, мы могли бы использовать
cut()