【发布时间】:2019-02-01 08:51:44
【问题描述】:
我有一个类似于以下结构的数据框:
set.seed(123)
df<-data_frame(SectionName = rep(letters[1:2], 50),
TimeSpentSeconds = sample(0:360, 100, replace = TRUE),
Correct = sample(0:1, 100, replace = TRUE))
我想通过将 TimeSpentSeconds 的所有值纳入特定范围(小于 30、30-60 之间、60-90 之间、...、大于 180)来总结此数据框,将时间标记为这些范围,按 SectionName 对它们进行分组,并找到正确列的总和,以便生成的数据框看起来像这样:
TimeGroup SectionName Correct
<fct> <chr> <int>
1 LessThan30Secs a 2
2 LessThan30Secs b 3
3 30-60 Seconds a 4
4 30-60 Seconds b 3
5 60-90 Seconds a 2
6 60-90 Seconds b 3
7 90-120 Seconds a 4
8 90-120 Seconds b 0
9 120-150 Seconds a 4
10 120-150 Seconds b 0
11 150-180 Seconds a 1
12 150-180 Seconds b 2
13 GreaterThan180Seconds a 11
14 GreaterThan180Seconds b 11
我能够使用下面的 if-else 代码成功地做到这一点,在该代码中,我将所有时间都变成了一个带有适当标签、分组和汇总的新列:
x <- c("LessThan30Secs", "30-60 Seconds", "60-90 Seconds","90-120 Seconds",
"120-150 Seconds", "150-180 Seconds", "GreaterThan180Seconds")
df %>%
mutate(TimeGroup = if_else(TimeSpentSeconds >= 0 & TimeSpentSeconds <= 30, "LessThan30Secs",
if_else(TimeSpentSeconds > 30 & TimeSpentSeconds <= 60, "30-60 Seconds",
if_else(TimeSpentSeconds > 60 & TimeSpentSeconds <= 90, "60-90 Seconds",
if_else(TimeSpentSeconds > 90 & TimeSpentSeconds <= 120, "90-120 Seconds",
if_else(TimeSpentSeconds > 120 & TimeSpentSeconds <= 150, "120-150 Seconds",
if_else(TimeSpentSeconds > 150 & TimeSpentSeconds <= 180, "150-180 Seconds",
if_else(TimeSpentSeconds > 180, "GreaterThan180Seconds", "")))))))) %>%
mutate(TimeGroup = factor(TimeGroup, levels = x)) %>%
arrange(TimeGroup) %>%
group_by(TimeGroup, SectionName) %>%
summarise(Correct = sum(Correct))
但是,必须有更好的方法来做到这一点。我考虑过写一个函数,但因为我不擅长写函数,所以没有走得太远。
是否有人对通过我没有想到的 dplyr 方法完成相同输出的更优雅方式有任何想法,编写自定义函数可能在某些时候使用 purrr 包或其他一些 r 函数?
【问题讨论】:
-
不要使用
if_else,而是尝试使用cut或findInterval,即df %>% group_by(TimeGroup = cut(TimeSpentSeconds, breaks = c(seq(0, 180, by = 30), Inf)), SectionName) %>% summarise(Correct = sum(Correct)) -
最好有一个
set.seed以使其可重现 -
虽然在这种情况下
findInterval是更好的解决方案,但如果间隔不是完全连续的,那么使用dplyr::case_when会更合适。