在两个日期之间筛选数据框的子集。

37

我正在使用自1993年以来的巴西指数(IBOV)的日回报率,我正在尝试找出在两个日期之间进行子集分析的最佳方法。

数据框(IBOV_RET)如下:

head(IBOV_RET)
        DATE    1D_RETURN
1 1993-04-28 -0.008163265
2 1993-04-29 -0.024691358
3 1993-04-30  0.016877637
4 1993-05-03  0.000000000
5 1993-05-04  0.033195021
6 1993-05-05 -0.012048193
...

我设置了两个变量DATE1DATE2作为日期。

DATE1 <- as.Date("2014-04-01")
DATE2 <- as.Date("2014-05-05")

使用这段代码我能创建一个新的子集:

TEST <- IBOV_RET[IBOV_RET$DATE >= DATE1 & IBOV_RET$DATE <= DATE2,]

它起作用了,但我想知道是否有更好的方法在两个日期之间对数据进行子集操作,也许可以使用 subset


2
如果你将你的数据框命名为df,日期命名为t1t2,你可以使用以下更简洁的代码:df[df$Date %in% t1:t2, ]。需要说明的是,t1:t2适用于日期,因此你不需要使用不等式。 - PatrickT
8个回答

24

正如 @MrFlick 已经指出的那样,您无法避免子集逻辑的基本原理。 使得更容易为您子集化特定数据框的一种方法是定义一个函数,该函数接受两个输入,例如在您的示例中使用 DATE1DATE2,然后根据这些子集参数返回 IBOV_RET 的子集。

myfunc <- function(x,y){IBOV_RET[IBOV_RET$DATE >= x & IBOV_RET$DATE <= y,]}

DATE1 <- as.Date("1993-04-29")
DATE2 <- as.Date("1993-05-04")

Test <- myfunc(DATE1,DATE2)    

#> Test
#        DATE  X1D_RETURN
#2 1993-04-29 -0.02469136
#3 1993-04-30  0.01687764
#4 1993-05-03  0.00000000
#5 1993-05-04  0.03319502

您还可以直接在myfunc中输入具体日期:

myfunc(as.Date("1993-04-29"),as.Date("1993-05-04")) #will produce the same result

14
你可以使用 subset() 函数结合 & 运算符:
subset(IBOV_RET, DATE1> XXXX-XX-XX & DATE2 < XXXX-XX-XX)

更新以更加"tidyverse导向"的方式:

IBOV_RET %>%
  filter(DATE1 > XXXX-XX-XX, DATE2 < XXXX-XX-XX) #comma same as &

4

提取日期范围没有其他真正的方法。逻辑与提取数值范围的逻辑相同,只需进行显式的日期转换即可。您可以使用subsetwith缩短子集任务的长度,就像任何其他子集任务一样。您可以使用cut将范围分成间隔(有一个特定的cut.Date重载)。但是基本的R语言没有指定日期文字的方式,因此您不能避免转换。我无法想象您可能会考虑什么其他类型的语法。


3

关于:

DATE1 <- as.Date("1993-04-29")
DATE2 <- as.Date("1993-05-04")

# creating a data range with the start and end date:
dates <- seq(DATE1, DATE2, by="days")

IBOV_RET <- subset(IBOV_RET, DATE %in% dates)

3

我相信lubridate可以帮助解决这个问题;

daterange <- interval(DATE1, DATE2)
TEST <- IBOV_RET[which(Date %within% daterange),]

1

我有点喜欢dplyr
所以如果你

>library("dplyr")

然后,就像你所做的一样:

>Date1<-as.Date("2014-04-01")  
>Date2<-as.Date("2014-05-05")

最后

>test<-filter(IBOV_RET, filter(DATE>Date1 & DATE<Date2))

这样两次调用filter是没有意义的。 - camille

1

您可以将字符串转换为日期后,使用 R 的 between() 函数:

df %>%
    filter(between(date_column, as.Date("string-date-lower-bound"), as.Date("string-date-upper-bound")))

0
Test = IBOV_RET[IBOV_RET$Date => "2014-04-01" | IBOV_RET$Date <= "1993-05-04"]

在这里,我正在使用“或”函数|其中数据应大于特定数据或数据应小于等于此日期。


4
虽然这段代码可能解决了问题,但是包括一些解释来说明这个解决方案是如何解决问题的会有助于提高你的回答的质量,并且可能会得到更多的赞同。请记住,你所回答的问题不仅是为了当前提问者,也是为未来的读者。请编辑你的回答并添加解释,同时指出限制和假设的范围。 - Yunnosch
1
@Yunnosch的评论始终值得记在心中,但在这里尤其如此,因为社区已经验证了几个答案。您的答案与现有答案有何不同?在什么情况下可能更受欢迎? - Jeremy Caney
对于延迟回复,我很抱歉。 - Gaurav

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接