使用两个日期列作为参考计算每个日历月的人次
Calculate person-time per calendar month using two date columns as references
我在 R 中有一个如下所示的数据框:
### Packages
library(tidyverse)
library(Epi)
library(survival)
library(lubridate)
### Create data:
End_Date <- as.Date("1968-01-01") + days(sample (c(250:365), size=500, replace =T))
Example_DF <- as.data.frame(End_Date)
Example_DF$Start_Date <- as.Date("1968-01-01")
Example_DF$Exposure <- Example_DF$End_Date - days(sample (c(1:249), size=500, replace =T))
Example_DF$ID <- seq(1,500,1)
我想要做的是为从 1968-01 到 1969-05(包括 1969-05)的每个日历月创建两个新列,每个日历月总结每个人(ID)的人时天数分别提供未曝光和曝光。例如,这些列可以称为 1968_01_Unexposed、1968_01_Exposed 等
曝光日期可在曝光列中找到。因此,我最终想要的是一个包含 41 列的数据框(原始数据框中的 4 列加上 34 列(1968-01 和 1969-05 之间每 17 个日历月 2 列))。例如,ID 1 在 1968-01 年有 31 天未暴露,1968-01 有 0 天暴露,直到 1968-07,其中 ID 1 有 10 天未暴露和 21 天暴露。
有人知道如何以方便的方式完成此操作吗?
以下内容应该可以帮助您前进。事实上,您已经根据问题描述的最后一段自己开发了部分“算法”。
使用 {tidyverse}
和 tibbles
/data frames
尝试在 vectors/columns 中思考,然后以更易读的 wide
方式呈现结果.
我演示了您如何使用前 2 个条目解决它的初始部分,并解决了天数的逻辑条件。
我留给您将此方法应用于暴露的日子,并阅读 {tidyr}
的 pivot_wider()
以将您的结果分布在所需的列中。
虽然您提供了一些示例数据并因此提供了一个可重现的示例,但该示例似乎无法运行 17 个月。我没有检查示例以进一步保持一致性。
library(tidyverse)
library(lubridate)
# first problem - each ID needs a month entry for our time horizon ---------------
## define the time horizon
Month_Bin <- seq(from = min(Example_DF$Start_Date)
, to = max(Example_DF$End_Date)
, by = "month")
## expand your (here first 2 entries) over the time horizon
Example_DF[1:2,] %>% # with [1:2,] the df is truncated to the first 2 rows - remove for full example
expand(ID, Month_Bin)
# combine with original data set to calculate conditions -----------------------
Example_DF[1:2,] %>%
expand(ID, Month_Bin) %>%
left_join(Example_DF, by = "ID")
# with this data we can now work on the conditions and --------------------------
# determine the days
Example_DF[1:2,] %>%
expand(ID, Month_Bin) %>%
left_join(Example_DF, by = "ID") %>%
## --------------- let's define whether the Month_Bin is before Exposure
## --------------- lubridate let's you work with "floored" dates ~ first of month
mutate(
Unexposed = floor_date( Exposure, "month") > floor_date(Month_Bin, "month")
, Exposed = floor_date(Exposure, "month") < floor_date(Month_Bin, "month")) %>%
## -------------- now you can detemine the days per month based on the condition
## -------------- multiple if-else() conditions are nicely packed into case_when
mutate(
Unexposed_Days = case_when(
Unexposed & !Exposed ~ days_in_month(Month_Bin)
,!Unexposed & !Exposed ~ as.integer(difftime(Exposure, Month_Bin, "days"))
,TRUE ~ as.integer(NA) # case_when() requires type consistency for default
)
) %>%
#--------------- for presentation I force the first 20 rows (ignore this)
head(20)
这产生:
# A tibble: 20 x 8
ID Month_Bin End_Date Start_Date Exposure Unexposed Exposed Unexposed_Days
<dbl> <date> <date> <date> <date> <lgl> <lgl> <int>
1 1 1968-01-01 1968-09-21 1968-01-01 1968-02-25 TRUE FALSE 31
2 1 1968-02-01 1968-09-21 1968-01-01 1968-02-25 FALSE FALSE 24
3 1 1968-03-01 1968-09-21 1968-01-01 1968-02-25 FALSE TRUE NA
4 1 1968-04-01 1968-09-21 1968-01-01 1968-02-25 FALSE TRUE NA
5 1 1968-05-01 1968-09-21 1968-01-01 1968-02-25 FALSE TRUE NA
6 1 1968-06-01 1968-09-21 1968-01-01 1968-02-25 FALSE TRUE NA
7 1 1968-07-01 1968-09-21 1968-01-01 1968-02-25 FALSE TRUE NA
8 1 1968-08-01 1968-09-21 1968-01-01 1968-02-25 FALSE TRUE NA
9 1 1968-09-01 1968-09-21 1968-01-01 1968-02-25 FALSE TRUE NA
10 1 1968-10-01 1968-09-21 1968-01-01 1968-02-25 FALSE TRUE NA
11 1 1968-11-01 1968-09-21 1968-01-01 1968-02-25 FALSE TRUE NA
12 1 1968-12-01 1968-09-21 1968-01-01 1968-02-25 FALSE TRUE NA
13 2 1968-01-01 1968-12-11 1968-01-01 1968-06-21 TRUE FALSE 31
14 2 1968-02-01 1968-12-11 1968-01-01 1968-06-21 TRUE FALSE 29
15 2 1968-03-01 1968-12-11 1968-01-01 1968-06-21 TRUE FALSE 31
16 2 1968-04-01 1968-12-11 1968-01-01 1968-06-21 TRUE FALSE 30
17 2 1968-05-01 1968-12-11 1968-01-01 1968-06-21 TRUE FALSE 31
18 2 1968-06-01 1968-12-11 1968-01-01 1968-06-21 FALSE FALSE 20
19 2 1968-07-01 1968-12-11 1968-01-01 1968-06-21 FALSE TRUE NA
20 2 1968-08-01 1968-12-11 1968-01-01 1968-06-21 FALSE TRUE NA
您应该能够构建暴露案例所需的天数。
然后继续阅读 {tidyr}
和 pivot_longer
,将您的长 table 扩展为您想要的宽格式。
我在 R 中有一个如下所示的数据框:
### Packages
library(tidyverse)
library(Epi)
library(survival)
library(lubridate)
### Create data:
End_Date <- as.Date("1968-01-01") + days(sample (c(250:365), size=500, replace =T))
Example_DF <- as.data.frame(End_Date)
Example_DF$Start_Date <- as.Date("1968-01-01")
Example_DF$Exposure <- Example_DF$End_Date - days(sample (c(1:249), size=500, replace =T))
Example_DF$ID <- seq(1,500,1)
我想要做的是为从 1968-01 到 1969-05(包括 1969-05)的每个日历月创建两个新列,每个日历月总结每个人(ID)的人时天数分别提供未曝光和曝光。例如,这些列可以称为 1968_01_Unexposed、1968_01_Exposed 等
曝光日期可在曝光列中找到。因此,我最终想要的是一个包含 41 列的数据框(原始数据框中的 4 列加上 34 列(1968-01 和 1969-05 之间每 17 个日历月 2 列))。例如,ID 1 在 1968-01 年有 31 天未暴露,1968-01 有 0 天暴露,直到 1968-07,其中 ID 1 有 10 天未暴露和 21 天暴露。
有人知道如何以方便的方式完成此操作吗?
以下内容应该可以帮助您前进。事实上,您已经根据问题描述的最后一段自己开发了部分“算法”。
使用 {tidyverse}
和 tibbles
/data frames
尝试在 vectors/columns 中思考,然后以更易读的 wide
方式呈现结果.
我演示了您如何使用前 2 个条目解决它的初始部分,并解决了天数的逻辑条件。
我留给您将此方法应用于暴露的日子,并阅读 {tidyr}
的 pivot_wider()
以将您的结果分布在所需的列中。
虽然您提供了一些示例数据并因此提供了一个可重现的示例,但该示例似乎无法运行 17 个月。我没有检查示例以进一步保持一致性。
library(tidyverse)
library(lubridate)
# first problem - each ID needs a month entry for our time horizon ---------------
## define the time horizon
Month_Bin <- seq(from = min(Example_DF$Start_Date)
, to = max(Example_DF$End_Date)
, by = "month")
## expand your (here first 2 entries) over the time horizon
Example_DF[1:2,] %>% # with [1:2,] the df is truncated to the first 2 rows - remove for full example
expand(ID, Month_Bin)
# combine with original data set to calculate conditions -----------------------
Example_DF[1:2,] %>%
expand(ID, Month_Bin) %>%
left_join(Example_DF, by = "ID")
# with this data we can now work on the conditions and --------------------------
# determine the days
Example_DF[1:2,] %>%
expand(ID, Month_Bin) %>%
left_join(Example_DF, by = "ID") %>%
## --------------- let's define whether the Month_Bin is before Exposure
## --------------- lubridate let's you work with "floored" dates ~ first of month
mutate(
Unexposed = floor_date( Exposure, "month") > floor_date(Month_Bin, "month")
, Exposed = floor_date(Exposure, "month") < floor_date(Month_Bin, "month")) %>%
## -------------- now you can detemine the days per month based on the condition
## -------------- multiple if-else() conditions are nicely packed into case_when
mutate(
Unexposed_Days = case_when(
Unexposed & !Exposed ~ days_in_month(Month_Bin)
,!Unexposed & !Exposed ~ as.integer(difftime(Exposure, Month_Bin, "days"))
,TRUE ~ as.integer(NA) # case_when() requires type consistency for default
)
) %>%
#--------------- for presentation I force the first 20 rows (ignore this)
head(20)
这产生:
# A tibble: 20 x 8
ID Month_Bin End_Date Start_Date Exposure Unexposed Exposed Unexposed_Days
<dbl> <date> <date> <date> <date> <lgl> <lgl> <int>
1 1 1968-01-01 1968-09-21 1968-01-01 1968-02-25 TRUE FALSE 31
2 1 1968-02-01 1968-09-21 1968-01-01 1968-02-25 FALSE FALSE 24
3 1 1968-03-01 1968-09-21 1968-01-01 1968-02-25 FALSE TRUE NA
4 1 1968-04-01 1968-09-21 1968-01-01 1968-02-25 FALSE TRUE NA
5 1 1968-05-01 1968-09-21 1968-01-01 1968-02-25 FALSE TRUE NA
6 1 1968-06-01 1968-09-21 1968-01-01 1968-02-25 FALSE TRUE NA
7 1 1968-07-01 1968-09-21 1968-01-01 1968-02-25 FALSE TRUE NA
8 1 1968-08-01 1968-09-21 1968-01-01 1968-02-25 FALSE TRUE NA
9 1 1968-09-01 1968-09-21 1968-01-01 1968-02-25 FALSE TRUE NA
10 1 1968-10-01 1968-09-21 1968-01-01 1968-02-25 FALSE TRUE NA
11 1 1968-11-01 1968-09-21 1968-01-01 1968-02-25 FALSE TRUE NA
12 1 1968-12-01 1968-09-21 1968-01-01 1968-02-25 FALSE TRUE NA
13 2 1968-01-01 1968-12-11 1968-01-01 1968-06-21 TRUE FALSE 31
14 2 1968-02-01 1968-12-11 1968-01-01 1968-06-21 TRUE FALSE 29
15 2 1968-03-01 1968-12-11 1968-01-01 1968-06-21 TRUE FALSE 31
16 2 1968-04-01 1968-12-11 1968-01-01 1968-06-21 TRUE FALSE 30
17 2 1968-05-01 1968-12-11 1968-01-01 1968-06-21 TRUE FALSE 31
18 2 1968-06-01 1968-12-11 1968-01-01 1968-06-21 FALSE FALSE 20
19 2 1968-07-01 1968-12-11 1968-01-01 1968-06-21 FALSE TRUE NA
20 2 1968-08-01 1968-12-11 1968-01-01 1968-06-21 FALSE TRUE NA
您应该能够构建暴露案例所需的天数。
然后继续阅读 {tidyr}
和 pivot_longer
,将您的长 table 扩展为您想要的宽格式。