data.frame 中的子集特定日期(年和月)
Subset specific dates (year and month) from data.frame
这是我的 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
开始的技巧,而无需在代码中手动添加日期?
谢谢
####更新
如果我在 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
谢谢
根据您共享的数据,Date
列的 class 是因素。我们将它们转换为 Date
class 并提取月份和年份部分并将其与 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
尝试
S = sapply(dates, function(d) { grep(d, df[,2]) })
df[S,]
@eipi10 在评论中指出:
df[df$Date %in% as.Date(paste0(dates,"-01")), ]
这对我更新的问题很有效。
谢谢
这里有一些解决方案。它们 (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"
class 给出相同的结果。这段代码更好一些,但确实需要一个包。
library(zoo)
subset(df2, as.yearmon(Date) %in% as.yearmon(dates))
您的日期格式为字符串,因此使用起来有些困难。通常,最好将它们格式化为实际的日期对象。这可以使用 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
对象中的任何月份相匹配。这给出了你想要的输出。
但是,也许您只想要您提供的组合。所以例如1980 年只有在第 2 个月出现时才可以。如果是这样,那就有点复杂了。这可以通过多种方式完成,但我选择了一种功能性方法。这执行起来不是最快的,但是编写起来很快而且非常灵活。
#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
函数的作用是遍历数据框中的每个日期,并遍历每个 year/month 组合。然后它会检查年份和月份是否与该特定组合相匹配。如果三个组合中的任何一个匹配(因此 any
),则该行 returns TRUE
。
这是我的 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
开始的技巧,而无需在代码中手动添加日期?
谢谢
####更新如果我在 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
谢谢
根据您共享的数据,Date
列的 class 是因素。我们将它们转换为 Date
class 并提取月份和年份部分并将其与 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
尝试
S = sapply(dates, function(d) { grep(d, df[,2]) })
df[S,]
@eipi10 在评论中指出:
df[df$Date %in% as.Date(paste0(dates,"-01")), ]
这对我更新的问题很有效。
谢谢
这里有一些解决方案。它们 (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"
class 给出相同的结果。这段代码更好一些,但确实需要一个包。
library(zoo)
subset(df2, as.yearmon(Date) %in% as.yearmon(dates))
您的日期格式为字符串,因此使用起来有些困难。通常,最好将它们格式化为实际的日期对象。这可以使用 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
对象中的任何月份相匹配。这给出了你想要的输出。
但是,也许您只想要您提供的组合。所以例如1980 年只有在第 2 个月出现时才可以。如果是这样,那就有点复杂了。这可以通过多种方式完成,但我选择了一种功能性方法。这执行起来不是最快的,但是编写起来很快而且非常灵活。
#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
函数的作用是遍历数据框中的每个日期,并遍历每个 year/month 组合。然后它会检查年份和月份是否与该特定组合相匹配。如果三个组合中的任何一个匹配(因此 any
),则该行 returns TRUE
。