我希望将数据分成分位数,与this great question
相同问题是我想每天按时间顺序进行:
set.seed(123)
temp.all <- data.frame(date = c(rep(Sys.Date() - 1, 12), rep(Sys.Date(), 12)),
name=letters[c(1:12, 1:12)], value=rnorm(24))
目前,我正在使用for循环解决问题:
library(dplyr)
for (d in unique(temp.all$date)) {
temp = filter(temp.all, date == d)
temp$quartile <- with(temp, factor(
findInterval( val, c(-Inf,
quantile(val, probs=c(0.25, .5, .75)), Inf) , na.rm=TRUE),
labels=c("Q1","Q2","Q3","Q4")
))
# ...and doing rbind on 'temp' to reconstruct temp.all with quartiles
}
关于如何避免可怕的for循环的任何想法?可能有group_by
方式吗?
答案 0 :(得分:4)
使用group_by
即可:
library(lubridate)
temp.all = temp.all %>%
# lubridate::date(date) might be necessary if you have datetimes
group_by(date) %>%
mutate(quartile = cut(value, breaks = 4, labels = paste0("Q", 1:4)))
dplyr
还有一个函数ntile
,其行为应与cut
类似,并且应该给出相同的结果。
答案 1 :(得分:1)
为了完整(并纠正错误的答案),这里也是一个data.table
解决方案:
library(data.table)
setDT(temp.all)[, quartile := cut(value, breaks = 4L, labels = paste0("Q", 1:4)), by = date]
temp.all
date name value quartile 1: 2017-08-28 a -0.56047565 Q1 2: 2017-08-28 b -0.23017749 Q2 3: 2017-08-28 c 1.55870831 Q4 4: 2017-08-28 d 0.07050839 Q2 5: 2017-08-28 e 0.12928774 Q2 6: 2017-08-28 f 1.71506499 Q4 ... 18: 2017-08-29 f -1.96661716 Q1 19: 2017-08-29 g 0.70135590 Q3 20: 2017-08-29 h -0.47279141 Q2 21: 2017-08-29 i -1.06782371 Q1 22: 2017-08-29 j -0.21797491 Q2 23: 2017-08-29 k -1.02600445 Q2 24: 2017-08-29 l -0.72889123 Q2 date name value quartile
请注意,结果按照OP的要求按date
进行分组,而不是day(date)
按{em>}汇总日期,例如1月1日,2月1日,3月1日等等。
进一步注意,只有一个额外的列quartile
被添加到temp.all
到位,即不复制整个数据集以节省内存和时间(在处理大型数据集时可能会变得相关。)