{r setup, include=FALSE} knitr::opts_chunk$set(eval = FALSE) {r message=FALSE, warning=FALSE, include=FALSE} library(data.table) library(tidyverse) library(lubridate)
新增
- duration in filter
- 目录
- duration
- 整理的lubridate的使用技巧
整理
{r echo=FALSE, message=FALSE, warning=FALSE} library(tidyverse) installed.packages() %>% as_tibble() %>% filter(Package == "lubridate") %>% select(Package,Version,Built)
{r} library(lubridate)
as date-times 系列
和 @base 重合很多,但是也很比较好的功能。
as_date
{r} as_date(0) as_date(1)
一天一单位
{r} sample_date <- "2017-01-01 as_date(sample_date) as.Date(sample_date)
as_date替换as.Date。
as_datetime
{r} as_datetime(0) as_datetime(1) as_datetime(10)
一秒一单位。
as.hms
{r} hms::as.hms(0) hms::as.hms(1)
这个功能很好, @base 应该没有。
round
{r} d <- "2018-05-03 11:19:10 CST d <- as_datetime(d) d floor_date(d,unit = "hour") ceiling_date(d,unit = "hour") round_date(d,unit = "hour") rollback(d) rollback(d,roll_to_first=T)
floor_date()$\to$floor$\to$round down$\to$向下取整ceiling_date()$\to$ceiling$\to$round up$\to$向上取整round_date()$\to$round$\to$round nearest$\to$就近取整rollback方便去月初月末数据,这里最好的是月末数据的取法,因为每个月最后一天不是一致的。
parse date-times
在 @base 中,
deparse函数将表达式string化parse函数将string表达式化
一因此这里也是将string转化为时间变量的意思。 因此要控制这里的输入是string。
{r} ymd_hms("2018-05-03 11:19:10 CST") yq("2018:Q1")
{r} date_decimal(2017.5, tz = "Asia/Shanghai")
date_decimal函数的输入是numeric,2017.5等价于$2017+\frac{5}{10} \cdot 1年$- 时区指定
tz = "Asia/Shanghai"
time zones
查看时区可以用 @base 的OlsonNames()函数。
{r} OlsonNames() %>% as_tibble() %>% filter(value %in% str_subset(value, "Shanghai|Chicago"))
{r} d2 <- ymd_hms(d) d2 with_tz(d2,tzone = "US/Pacific") force_tz(d2,tzone = "US/Pacific")
with_tz的输入必须是时间变量而非string。with_tz是转换时差force_tz是保持时间不变,改变时区。
Math with Date-times
吃完饭,来搞一搞。
这里主要区分periods和durations两种函数
- periods:
minutes等*s - durations:
dminutes等d*s
它们之间的区别是periods不考虑美国冬令时等转换、闰年转换等,因此推荐使用durations。
{r} ymd_hms("2018-05-03 12:52:10 CST") + dminutes(30)
interval()函数会建立成特定的时间变量,但是我觉得我使用的少。
{r} interval( ymd_hms("2018-05-03 12:52:10 CST") + dminutes(30), ymd_hms("2018-05-03 12:52:10 CST") ) %>% as_tibble()
duration
区别于interval
{r} library(lubridate) interval(ymd("2019-03-01"),ymd("2019-02-01")) %>% as.duration() (ymd("2019-03-01")-ymd("2019-02-01")) (ymd("2019-03-01")-ymd("2019-02-01")) %>% as.integer()
{r} (ymd_hms("2019-03-01 00:00:00")-ymd_hms("2019-03-01 01:00:00")) %>% as.integer() %>% dhours()
d*s 函数只要回传的数字,并且*反馈正确的单位即可。
未整理
{r} # 生成 100 个日期,从2018-01-01开始 set.seed(42) n <- 100 dt <- data.table(date = seq(ymd("2018-01-01"),length.out = n, by = "day"), x = runif(n) ) dt %>% head()
by = "day"是递增按日计算。
按照周进行分类[@大猫的R语言课堂2018]
{r} dt %>% mutate(week = week(date)) %>% group_by(week) %>% summarise(avg = mean(x))
week是lubridate的函数。
按照星期进行分类[@大猫的R语言课堂2018]
{r} dt %>% mutate(weekday = wday(date)) %>% group_by(weekday) %>% summarise(avg = mean(x))
wday是lubridate的函数,表达星期几。
按照"每个三天"分类[@大猫的R语言课堂2018]
{r} dt %>% mutate(three.day = ceiling_date(date,unit = "3 days")) %>% head()
ceiling_date是lubridate的函数, unit = "3 days"表达间隔三天。
转换成"%Y-%m"的方法[@大猫的R语言课堂2018]
format(transactiondate, "%Y-%m") 但是这是文本格式。
这是DataCamp出的xts包的 cheatsheet
当对月份设为group,进行汇总时,可以使用xts包,也可以使用lubridate包,进行时间变量的计算。 通过year、month函数提取时间变量的年和月,仿造day=1, 然后通过make_date(year,month,day)函数进行合并。 这里需要对时间变量再转换as.POSIXct.Date。因为在ggplot中表示时,scale_x_datetime(date_breaks = "1 month")函数需要x为POSIXct.Date格式。
时区的bug解决[@大猫的R语言课堂2018]
我估计是我的时区选的有问题。 发现我的input的时候是UTC时区。 所以要修改成r Sys.timezone()。 并且with_tz(.,tzone = "Asia/Shanghai")可以查看具体时间在本时区的表达情况。 mutate(start = ymd_hms(as.character(start), tz = "Asia/Shanghai"))这是一个置换不同时区的方式。 综上,excel处理时间的函数有毒。
少用ymd_hms函数[@大猫的R语言课堂2018]
最后转化成double了。 mutate(start = ymd_hms(start))中ymd_hms常常会让一个时间变量变成double格式,这个很麻烦,因为转换都需要as.POSIXct(as.numeric(time), origin='1970-01-01')中的origin,这个不知道啊,所以坑。
duration in filter
as.integer函数使得duration可以在filter中进行筛选。
{r eval=F} library(lubridate) data_3 %>% select(1:5) %>% transmute(datetime = make_datetime(X1,X2,X3,X4,X5)) %>% arrange(datetime) %>% mutate(duration = interval(datetime,lag(datetime)) %>% as.duration(), duration_int = as.integer(duration)) %>% filter(duration_int != -300) ## %within% 函数
```{r} ref_tbl <- tibble( placement = c(“NewYorkTimes_iPhone”,“NewYorkTimes_iPhone”), start = c(“2018-06-01”,“2018-06-26”), end = c(“2018-06-25”,“2018-06-30”), rate = c(5,7) ) %>% mutate_at(vars(start, end),as.Date) des_tbl <- tibble( placement = “NewYorkTimes_iPhone”, date = “2018-06-15”, rate = 5 ) %>% mutate(date = as.Date(date)) ref_tbl des_tbl
ref_tbl %>% left_join(des_tbl, by = c(“placement”,“rate”)) %>% mutate( ifelse(date %within% interval(start,end),1,0) )
`%within%` 和 `interval` 是`lubridate`的函数,主要算时间区间的。
I post an answer related to this function on [Stack Overflow](https://stackoverflow.com/questions/50751794/if-date-is-between-two-dates-find-value-using-shared-reference/50752551#50752551).
## 月首日 `floor_date`
参考 @Spring2018 的思路。
```
x <- ymd(c("2012-03-26", "2012-05-04", "2012-09-23", "2012-12-31"))
floor_date(x, "1 month")
floor_date(x, "1 month") %>% decimal_date()
以周四为首日的周度数据
date_add(date_add(makedate(year(inserttime),1), interval week(date_sub(inserttime,interval 4 day)) week), interval 3 day) as 发标时间,
date_add(makedate(year(inserttime),1): 201X-01-1date_sub(inserttime,interval 4 day): 倒退四天week(date_sub(inserttime,interval 4 day)): 倒退四天的占今年的星期数,所有的周五、周六、周日星期数不变,周一、周二、周三、周四都少加一个星期。date_sub(...,interval 3 day): 这里的计算还是不清楚
使用seq函数创建时间序列 [@LaBarr2018, Chapter 1.2]
seq(as.Date("2014-01-19"), length = 176, by = 7)
随机生成时间
as.POSIXct(" 2017-10-08 07:00:00") + runif(n=100, min=0, max=3600)
unix time converting
参考 @Eddelbuettel2012
{r} as.POSIXct(1352068320, origin="1970-01-01")
月度变化
floor(cohort_index/30/3600/24) 比这个包的函数精确好用。