每个 ID 按日期选择观察

Posted

技术标签:

【中文标题】每个 ID 按日期选择观察【英文标题】:Select observations by date per ID 【发布时间】:2022-01-03 05:51:00 【问题描述】:

我想按各个时间范围选择观察结果 - 我的模拟数据可以解释我需要什么:

有两个数据框:

event_data:包含在 某个日期。每个事件都是一个新的行,但是一个单独的 (由“event_person_id”标识的也可能经历不止一个 事件(可能是 2、3、4、5...)。 visit_data:包含与个人的所有个人联系。每一个 访问被分配给个人(“visit_person_id”)并具有 自己的访问日期。访问次数远多于活动。

Visit_data 最终包含的数据比我需要的多,因为我只想选择 visit_data 中发生在 "event_date" 加上两年之间的时间范围内的那些行

例如: Person_id 1 有两个事件 - 第一个在 2014 年 3 月 21 日,第二个在 2018 年 8 月 8 日,所以我想只选择 visit_data 中日期在 2014 年 3 月 21 日之间的那些行2016 年 3 月 21 日以及 2018 年 8 月 8 日至 2020 年 8 月 8 日之间。

我的想法是通过 person_id 加入 event_data 和 visit_data - 所以我有一个包含 visit_date 和 event_date 的新数据框,然后我可以选择相关信息,但我的方法并不完全正确(随机?)将第一个或第二个 event_date 分配给访问行 fe person_id 5 在 1988-12-15 进行了一次访问,但 event_date 是 2019-09-03 而不是 1988-03-04,因此此访问被忽略,因为 2019 不在1988 年到 1990 年。

如果我加入表格的想法完全错误,或者如果有更聪明的方法,我想学习这个更好的方法!

这是我的代码:

library(dplyr)
library(lubridate)

set.seed(123)

event_data <- data.frame(event_person_id = seq(1, 100, 1),
                         event_date = sample(seq(as.Date('1980/01/01'), as.Date('2010/12/31'), by="day"), 100),
                         age = round(runif(100, min = 1, max = 80)), 
                         bmi = round(runif(100, min = 19, max = 30)), 
                         amount = round(runif(100, min = 10, max = 10000)), 
                         stringsAsFactors = FALSE)

event_data2 <- data.frame(event_person_id = seq(1, 10, 1),
                         event_date = sample(seq(as.Date('2011/01/01'), as.Date('2020/12/31'), by="day"), 10),
                         age = round(runif(10, min = 1, max = 80)), 
                         bmi = round(runif(10, min = 19, max = 30)), 
                         amount = round(runif(10, min = 10, max = 10000)), 
                         stringsAsFactors = FALSE)

event_data_total <- rbind(event_data, event_data2)

visit_data <- data.frame(visit_person_id = round(runif(10000, min = 1, max = 100)),
                         visit_id = seq(1, 10000, 1),
                         visit_date = sample(seq(as.Date('1980/01/01'), as.Date('2020/12/31'), by="day"), 10000),
                         var1 = round(runif(10000, min = 1, max = 500)), 
                         var2 = round(runif(10000, min = 1, max = 1000)), 
                         var3 = round(runif(10000, min = 1, max = 9000)), 
                         stringsAsFactors = FALSE)

data_joined <-
  dplyr::inner_join(visit_data, event_data_total, by = c('visit_person_id' = 'event_person_id')) %>% 
  arrange(visit_date)

data_joined_final <- data_joined %>%
  filter(visit_date > event_date & visit_date < (event_date %m+% years(2)))

我真的很感谢你的帮助:)

【问题讨论】:

【参考方案1】:

在帮助方面相当新,所以请怜悯;)但据我了解,解决方案可能来自“data.table”“foverlaps”。通过重叠日期和 ID 连接。我不能 100% 确定您希望最终数据的准确程度,但这里有一个建议,您可以根据自己的具体需要进行修改。

library(dplyr)
library(lubridate)
library(data.table)


set.seed(123)

event_data <- data.frame(event_person_id = seq(1, 100, 1),
                         event_date = sample(seq(as.Date('1980/01/01'), as.Date('2010/12/31'), by="day"), 100),
                         age = round(runif(100, min = 1, max = 80)), 
                         bmi = round(runif(100, min = 19, max = 30)), 
                         amount = round(runif(100, min = 10, max = 10000)), 
                         stringsAsFactors = FALSE)

event_data2 <- data.frame(event_person_id = seq(1, 10, 1),
                          event_date = sample(seq(as.Date('2011/01/01'), as.Date('2020/12/31'), by="day"), 10),
                          age = round(runif(10, min = 1, max = 80)), 
                          bmi = round(runif(10, min = 19, max = 30)), 
                          amount = round(runif(10, min = 10, max = 10000)), 
                          stringsAsFactors = FALSE)

event_data_total <- rbind(event_data, event_data2)

visit_data <- data.frame(visit_person_id = round(runif(10000, min = 1, max = 100)),
                         visit_id = seq(1, 10000, 1),
                         visit_date = sample(seq(as.Date('1980/01/01'), as.Date('2020/12/31'), by="day"), 10000),
                         var1 = round(runif(10000, min = 1, max = 500)), 
                         var2 = round(runif(10000, min = 1, max = 1000)), 
                         var3 = round(runif(10000, min = 1, max = 9000)), 
                         stringsAsFactors = FALSE)


#create the end dates + 2 years
event_data_total$end_date <- event_data_total$event_date + years(2)

#set as data.table
DT1 <- data.table(visit_data)
DT2 <- data.table(event_data_total)

#set joining keys
setkey(DT2, event_person_id, event_date, end_date)

#create dublicate columns with the same names, used for foverlaps
DT1[, c("event_date", "end_date") := visit_date] 
DT1[, c("event_person_id") := visit_person_id] 

#join data
data_joined<-foverlaps(DT1, DT2)

# now you should be able to sort it with e.g.
dat <- data_joined[complete.cases(data_joined), ]

【讨论】:

嗨!很抱歉我的回复很晚 - 我无法更早地测试你的解决方案......它有效 - 非常感谢你:) 没问题,很高兴它有用

以上是关于每个 ID 按日期选择观察的主要内容,如果未能解决你的问题,请参考以下文章

根据条件按 ID 组合重叠日期

按最近日期订购日期-SQL 选择单个 ID

选择查询优化

Mysql按日期时间的日期部分分组,并为每个日期选择具有最大日期时间的行

MySQL 分区:按 ID 选择,但按日期删除

Postgresql 按日期和特定 ID 选择前 x 行