Tyl*_*ker -1 r dplyr tidyverse
我经常有数据集,我随着时间的推移有多个事件测量,我想在一个月内为每个事件采取最大日期.我这样做是通过创建年份和月份变量,然后按日期降序排序,然后是group_by除日期之外的所有变量,然后使用a slice来获取最大日期.我听到Hadely在视频中说这arrange是一个缓慢的操作.我想知道这样做的有效方法是在整齐的范围内.
请发布base,data.table,其他答案,以便其他用途可以从这个问题中受益,但我的愿望是一个整齐的方法.
library(tidyverse)
set.seed(10)
dat <- data_frame(
date = sample(seq(as.Date('1999/01/01'), as.Date('2001/01/01'), by="day"), 1000, TRUE),
cash = sample(1010:1030, 1000, TRUE),
stage = sample(LETTERS[1:7], 1000, TRUE)
) %>% distinct()
dat %>%
mutate(
year = format(date, '%Y'),
month = format(date, '%B')
) %>%
arrange(desc(date)) %>%
group_by(cash, stage, year, month) %>%
slice(1)
Run Code Online (Sandbox Code Playgroud)
OP不包括扩大基准的方法,所以我自己制作:
library(data.table)
library(dplyr)
n = 3e6
n_days = 20000
set.seed(10)
dat <- data_frame(
date = sample(
seq(as.Date('1999/01/01'), as.Date('1999/01/01') + n_days - 1, by="day")
, n, TRUE),
cash = sample(1010:1030, n, TRUE),
stage = sample(LETTERS[1:7], n, TRUE)
) %>% distinct()
DT = data.table(dat)[, date := as.IDate(date)]
Run Code Online (Sandbox Code Playgroud)
测试:
# OP's approach
system.time(
res <- dat %>%
mutate(
year = format(date, '%Y'),
month = format(date, '%B')
) %>%
arrange(desc(date)) %>%
group_by(cash, stage, year, month) %>%
slice(1)
)
# user system elapsed
# 9.44 0.09 9.54
# a data.table way
system.time({
DTres <- DT[, g := date - mday(date) + 1L ][order(-date), .SD[1L], by=.(cash, stage, g)]
})
# user system elapsed
# 0.51 0.00 0.52
# verify
fsetequal(
data.table(res[, c("cash","stage","date")])[, date := as.IDate(date)][],
DTres[, c("cash","stage","date")]
) # TRUE
Run Code Online (Sandbox Code Playgroud)
翻译回dplyr:
system.time({
newres <- dat %>% mutate(g = date - as.POSIXlt(date)$mday + 1) %>%
arrange(desc(date)) %>% group_by(cash, stage, g) %>% slice(1L)
})
# Error, who knows why?
system.time({
newres <- dat %>% mutate(g = date + 1 - date %>% as.POSIXlt %>% `[[`("mday")) %>%
arrange(desc(date)) %>% group_by(cash, stage, g) %>% slice(1L)
})
# user system elapsed
# 1.47 0.04 1.52
fsetequal(
data.table(res[c("date","cash","stage")]),
data.table(newres[c("date","cash","stage")])
) # TRUE
# or ...
iddat <- dat %>% mutate(date = data.table::as.IDate(date))
mday <- data.table::mday
system.time({
borrowres <- iddat %>% arrange(desc(date)) %>%
distinct(cash, stage, g = date - mday(date) + 1L)
})
# user system elapsed
# 0.92 0.02 0.94
fsetequal(
data.table(borrowres[names(DTres)]),
DTres
) # TRUE
Run Code Online (Sandbox Code Playgroud)
由于我调整相对时间没有太大变化n及n_days.感谢@Arun这种舍入方式.以前,我有过round(date, "months").似乎关键是使用算术代替format.我不确定时间上的剩余差异; 也许它可以通过使用dtplyr来解决.arrange %>% distinct除了清理语法之外,切换没有做太多.
旁注:我正在加载dplyr而不是tidyverse,因为我真的不知道后者包含什么.不过,我用tidyverse尝试了它并得到了相同的时间.
| 归档时间: |
|
| 查看次数: |
472 次 |
| 最近记录: |