R使用过滤器和管道过滤以日期为条件的大型数据框
R filter a large dataframe conditional on dates, using filter and pipes
我有一个大数据框,我想要 select 满足日期列条件的行。数据框类似于:
library(tidyverse)
library(lubridate)
curdate <- seq(as.Date("2000/1/1"), by = "month", length.out = 24)
expdate <- rep(seq(as.Date("2000/3/1"), by = "quarter", length.out = 12),2)
afactor <- rep(c("C","P"),12)
anumber <- runif(24)
df<-data.frame(curdate, expdate, afactor, anumber)
df$expdate[12]<-as.Date("2001-02-01")
我想获取到期日期 (expdate) 的月份比当前日期的月份 (curdate) 晚两个月的行。在这个例子中,我应该 select 这五个日期(第 1、7、12、13 和 19 行):
curdate expdate afactor anumber
2000-01-01 2000-03-01 C 0.6832251
2000-07-01 2001-09-01 C 0.2671076
2001-01-01 2000-03-01 C 0.2097065
2001-07-01 2001-09-01 C 0.9258450
2000-12-01 2001-02-01 P 0.4903951
首先,我为此使用了以下行:
df_select1 <- df %>% group_by(curdate, afactor) %>%
filter(month(expdate) == month(curdate)+2)
但它漏掉了月份是 11 月或 12 月的情况。例如这里,当 curdate 为 2000-12-01 时,它会忽略这种情况。所以我想添加一个条件,来处理这些情况。我写道:
df_select2 <- df %>% group_by(curdate, afactor) %>%
if_else(month(curdate)<11,
filter(month(expdate) == month(curdate)+2),
filter(month(expdate) == month(curdate)-10))
但我收到以下错误:condition
必须是逻辑向量,而不是 grouped_df/tbl_df/tbl/data.frame
对象。
我找到了以下解决方案,但当然还有更短的方法:
df_select1 <- df %>% group_by(curdate, afactor) %>%
filter(month(curdate)<11) %>%
filter(month(expdate) == month(curdate)+2)
df_select2 <- df %>% group_by(curdate, afactor) %>%
filter(month(curdate)>10) %>%
filter(month(expdate) == month(curdate)-10)
df_select <- full_join(df_select1, df_select2)
您可以使用 lubridate
中的 %m+% 运算符向 curdate
添加 2 个月:
df %>%
filter(months(expdate) == months(curdate %m+% months(2)))
这将考虑日历月的天数变化。
编辑
问题更新后,我从 base-R 添加了 months
函数。也可以使用 lubridate
中的 month
函数。
如果您要导入 lubridate,您可能还应该使用它的函数来计算月份。这些显然有点棘手,因为它们的长度不相等,例如为什么基本函数 difftime 不提供每月单位。
如果没有 if_else 函数,这将是您问题的解决方案:
df_select1 <- df %>% group_by(curdate, afactor) %>%
filter(expdate == curdate + months(2))
顺便说一下,只要您的数据始终是相应月份的第一天,您就不会 运行 遇到问题。不过,您必须决定在以下情况下应该发生什么:
ymd("2019-08-31")+months(1)
ymd("2019-01-29")+months(1)
由于显而易见的原因,这导致了 NA。如果发生这种情况,lubridate::add_with_rollback() 可以根据您的需要提供解决方案。
澄清问题后的编辑。如果您正在寻找那些与 curdate 相比,expdate 是“晚”两个月的日期,在特定意义上,您只比较它们的月份而不考虑年份,一个小的模运算可能会有所帮助:
df %>%
filter(lubridate::month(expdate) == (lubridate::month(curdate)+2) %% 12)
我有一个大数据框,我想要 select 满足日期列条件的行。数据框类似于:
library(tidyverse)
library(lubridate)
curdate <- seq(as.Date("2000/1/1"), by = "month", length.out = 24)
expdate <- rep(seq(as.Date("2000/3/1"), by = "quarter", length.out = 12),2)
afactor <- rep(c("C","P"),12)
anumber <- runif(24)
df<-data.frame(curdate, expdate, afactor, anumber)
df$expdate[12]<-as.Date("2001-02-01")
我想获取到期日期 (expdate) 的月份比当前日期的月份 (curdate) 晚两个月的行。在这个例子中,我应该 select 这五个日期(第 1、7、12、13 和 19 行):
curdate expdate afactor anumber
2000-01-01 2000-03-01 C 0.6832251
2000-07-01 2001-09-01 C 0.2671076
2001-01-01 2000-03-01 C 0.2097065
2001-07-01 2001-09-01 C 0.9258450
2000-12-01 2001-02-01 P 0.4903951
首先,我为此使用了以下行:
df_select1 <- df %>% group_by(curdate, afactor) %>%
filter(month(expdate) == month(curdate)+2)
但它漏掉了月份是 11 月或 12 月的情况。例如这里,当 curdate 为 2000-12-01 时,它会忽略这种情况。所以我想添加一个条件,来处理这些情况。我写道:
df_select2 <- df %>% group_by(curdate, afactor) %>%
if_else(month(curdate)<11,
filter(month(expdate) == month(curdate)+2),
filter(month(expdate) == month(curdate)-10))
但我收到以下错误:condition
必须是逻辑向量,而不是 grouped_df/tbl_df/tbl/data.frame
对象。
我找到了以下解决方案,但当然还有更短的方法:
df_select1 <- df %>% group_by(curdate, afactor) %>%
filter(month(curdate)<11) %>%
filter(month(expdate) == month(curdate)+2)
df_select2 <- df %>% group_by(curdate, afactor) %>%
filter(month(curdate)>10) %>%
filter(month(expdate) == month(curdate)-10)
df_select <- full_join(df_select1, df_select2)
您可以使用 lubridate
中的 %m+% 运算符向 curdate
添加 2 个月:
df %>%
filter(months(expdate) == months(curdate %m+% months(2)))
这将考虑日历月的天数变化。
编辑
问题更新后,我从 base-R 添加了 months
函数。也可以使用 lubridate
中的 month
函数。
如果您要导入 lubridate,您可能还应该使用它的函数来计算月份。这些显然有点棘手,因为它们的长度不相等,例如为什么基本函数 difftime 不提供每月单位。
如果没有 if_else 函数,这将是您问题的解决方案:
df_select1 <- df %>% group_by(curdate, afactor) %>%
filter(expdate == curdate + months(2))
顺便说一下,只要您的数据始终是相应月份的第一天,您就不会 运行 遇到问题。不过,您必须决定在以下情况下应该发生什么:
ymd("2019-08-31")+months(1)
ymd("2019-01-29")+months(1)
由于显而易见的原因,这导致了 NA。如果发生这种情况,lubridate::add_with_rollback() 可以根据您的需要提供解决方案。
澄清问题后的编辑。如果您正在寻找那些与 curdate 相比,expdate 是“晚”两个月的日期,在特定意义上,您只比较它们的月份而不考虑年份,一个小的模运算可能会有所帮助:
df %>%
filter(lubridate::month(expdate) == (lubridate::month(curdate)+2) %% 12)