这是我的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
是否有可能编写一个从df
和dates
开始执行此操作的唯一代码,而无需手动添加代码中的日期?
由于
#### 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
由于
答案 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 另一种可能性是将Date
和dates
转换为"yearmon"
类,给出相同的结果。这段代码有点好,但需要一个包。
library(zoo)
subset(df2, as.yearmon(Date) %in% as.yearmon(dates))