data.frame中的子集特定日期(年和月)

时间:2016-11-28 16:58:25

标签: r dataframe subset lubridate

这是我的data.frame:

df = read.table(text = 'ID   Date
1      1975-01-01
2      1980-02-01
3      1985-05-01
4      1990-07-01
5      1990-08-01
6      1993-01-01
7      1993-09-01', header = TRUE)

我需要通过选择特定日期(年和月)来创建子集。

我感兴趣的日期是:

dates = c('1980-02', '1990-07', '1993-09')

因此我的输出应为:

ID     Date
2      1980-02-01
4      1990-07-01
7      1993-09-01

是否有可能编写一个从dfdates开始执行此操作的唯一代码,而无需手动添加代码中的日期?

由于

#### UPDATE

如果我在df内的同一个月内收到多个观察结果,例如:

,该怎么办?
df2 = read.table(text = 'ID   Date
1      1975-01-01
2      1980-02-01
9      1980-02-01
3      1985-05-01
4      1990-07-01
12     1990-07-01
16     1990-07-01
5      1990-08-01
6      1993-01-01
7      1993-09-01
67     1993-09-01', header = TRUE)

新输出:

ID     Date
2      1980-02-01
9      1980-02-01
4      1990-07-01
12     1990-07-01
16     1990-07-01
7      1993-09-01
67     1993-09-01

由于

5 个答案:

答案 0 :(得分:2)

您的日期格式为字符串,因此有些难以使用。通常,将它们格式化为实际日期对象会更好。这可以使用the lubridate package完成。这就是我要做的。我使用 readr 包进行自动类型检测,使用 purrr 进行函数式编程。

library(pacman)
p_load(lubridate, readr, purrr)

df = read_table(
'ID   Date
1      1975-01-01
2      1980-02-01
9      1980-02-01
3      1985-05-01
4      1990-07-01
12     1990-07-01
16     1990-07-01
5      1990-08-01
6      1993-01-01
7      1993-09-01
67     1993-09-01'
)

dates = parse_date_time(c('1980-02', '1990-07', '1993-09'), orders = "Y-m")

#subset
df[year(df$Date) %in% year(dates) & month(df$Date) %in% month(dates), ]

其输出为:

# A tibble: 7 × 2
     ID       Date
  <int>     <date>
1     2 1980-02-01
2     9 1980-02-01
3     4 1990-07-01
4    12 1990-07-01
5    16 1990-07-01
6     7 1993-09-01
7    67 1993-09-01

因此,我们按照您的方式加载数据,但是使用 readr 来自动识别日期。然后,我们将年份与dates对象中任何年份匹配的行进行子集化,并且月份与dates对象中的任何月份匹配。这给出了你想要的输出。

然而,也许你只想要你给出的组合。所以例如如果它出现在第2个月,那么1980年是可以的。如果是这样,它会有点复杂。这可以通过多种方式完成,但我选择了一种功能性方法。这不是执行速度最快的,但编写速度快且非常灵活。

#subset stricter
inclusion_func = function(x, desired_dates) {
  #loop over each date
  map_lgl(x, function(date) {
    any(map_lgl(desired_dates, function(desired_date) {
      year(date) == year(desired_date) && month(date) == month(desired_date)
    })
    )
  })
}

df[inclusion_func(df$Date, dates), ]

其输出相同:

# A tibble: 7 × 2
     ID       Date
  <int>     <date>
1     2 1980-02-01
2     9 1980-02-01
3     4 1990-07-01
4    12 1990-07-01
5    16 1990-07-01
6     7 1993-09-01
7    67 1993-09-01

该功能的作用是循环数据框中的每个日期,并循环每年/每月组合。然后检查该特定组合的年和月是否匹配。如果三种组合中的任何一种匹配(因此any),则返回该行的TRUE

答案 1 :(得分:0)

根据您分享的数据,Date列的类别是因素。我们将它们转换为Date类并提取月份和年份部分并将其与dates向量相匹配,以获得匹配的df行号。

df[match(dates, format(as.Date(df$Date), "%Y-%m")), ]  

#   ID       Date
#2  2 1980-02-01
#4  4 1990-07-01
#7  7 1993-09-01

根据更新的问题,如果我们有多个匹配日期,我们可以使用%in%,这会为您提供所需的输出。

df2[format(as.Date(df2$Date), "%Y-%m") %in% dates, ]

#   ID       Date
#2   2 1980-02-01
#3   9 1980-02-01
#5   4 1990-07-01
#6  12 1990-07-01
#7  16 1990-07-01
#10  7 1993-09-01
#11 67 1993-09-01

答案 2 :(得分:0)

尝试

    S = sapply(dates, function(d) { grep(d, df[,2]) })
    df[S,]

答案 3 :(得分:0)

正如@ eipi10在评论中所指出的那样:

df[df$Date %in% as.Date(paste0(dates,"-01")), ]

这对我更新的问题很有用。

由于

答案 4 :(得分:0)

以下是一些解决方案。他们(i)与任何日期合作,而不仅仅是本月的第一个日期,(ii)保留输出中df2的顺序,(iii)紧凑,即每行一行,不需要多次提到df2

1)substr 这不使用任何包。

subset(df2, substr(Date, 1, 7) %in% dates)

,并提供:

   ID       Date
2   2 1980-02-01
3   9 1980-02-01
5   4 1990-07-01
6  12 1990-07-01
7  16 1990-07-01
10  7 1993-09-01
11 67 1993-09-01

2)zoo :: as.yearmon 另一种可能性是将Datedates转换为"yearmon"类,给出相同的结果。这段代码有点好,但需要一个包。

library(zoo)
subset(df2, as.yearmon(Date) %in% as.yearmon(dates))