问题描述
我在数据库中有一个数据框,其中包含我使用 RPostgres 提取的日期维度。每个“日期”的格式为“YYYY-MM-DD”。我想添加比初始日期早一年的新日期列(标记为“lookback_date”)。
明确地说,如果观察的“日期”是“2000-01-01”,我想在该观察中添加一个新的“lookback_date”,即“1999-01-01”。不幸的是,我无法弄清楚如何做到这一点。通常,我会使用 Lubridate,但是,据我所知,它不适用于 dbplyr。到目前为止,这是我的代码的简化版本。在 mutate 函数之前,我的实际代码中的所有内容都可以正常工作。
# Packages
library(dbplyr)
library(RPostgres)
# Connect to db
drv <- dbDriver("Postgres")
# Setup connect to db
conn <- dbConnect(drv,dbname = etc,)
# Define table to use in db
table <- tbl(conn,in_schema("xyz","abc"))
#Select columns and filter
base_data <- table %>%
#Filter for pertinent data
filter(date > as.Date("2018-01-01") & date <= as.Date("2020-01-01"))
modified_data <- base_data %>%
mutate(lookback_date = date - 365)
还有其他方法可以创建这个新的日期列吗?
谢谢!
解决方法
您认为 lubridate 和 dbplyr 不能很好地配合使用是正确的(现在)。因此,我使用 sql 片段进行了大部分 dbplyr 日期操作。
基于 this answer 和 this site,从日期中添加/减去时间的 postgresql 语法是:
SELECT old_date + INTERVAL '1 day' AS new_date;
基于此,我将尝试以下操作:
output = base_data %>% mutate(lookback_date = date - sql("INTERVAL '1 year'"))
当我使用模拟连接执行此操作时,它会生成正确的语法:
library(dplyr)
library(dbplyr)
df = data.frame(my_num = c(1,2,3),my_dates = as.Date(c('2000-01-01','2000-02-02','2000-03-03')))
df = tbl_lazy(df,con = simulate_postgres())
output = df %>% mutate(new_date = my_dates - sql("INTERVAL '1 year'"))
show_query(output)
# <SQL>
# SELECT `my_num`,`my_dates`,`my_dates` - INTERVAL '1 year' AS `new_date`
# FROM `df`
更新:根据评论,您首先要从日期时间转换为日期。
看来 dbplyr 确实支持将 as.Date
转换为 PostgreSQL(as.Date
是基础 R 的一部分,而不是 lubridate 的一部分)。因此,您可以使用以下内容将列转换(转换)为日期:
library(dplyr)
library(dbplyr)
df = data.frame(my_str = c('2000-01-01','2000-03-03'))
df = tbl_lazy(df,con = simulate_postgres())
output = df %>% mutate(my_date = as.Date(my_str))
show_query(output)
# <SQL>
# SELECT `my_str`,CAST(`my_str` AS DATE) AS `my_date`
# FROM `df`
似乎PostgreSQL也不允许你添加一年的间隔。另一种方法是从日期中提取年、月和日,在年中加一,然后重新组合。
按照这两个引用(postgre date references 和 date_part fuction)和 this 的答案,您可能需要如下内容:
output = df %>%
mutate(the_year = DATE_PART('year',my_date),the_month = DATE_PART('month',the_day = DATE_PART('day',my_date)) %>%
mutate(new_date = MAKE_DATE(the_year + 1,the_month,the_day)
,
您可以使用字符串将年份减去 1 并将其与日期和月份连接起来。我不确定这是否会转换为 sql !这也将防止闰年把日子弄乱。
base_data %>%
mutate(lookback_date = as.Date(paste0((as.numeric(substr(date,1,4)))-1,substr(date,5,10)),format="%Y-%m-%d"))