【问题标题】:Creating a new date variable that is on the same day of the week, within the same month, and year as original date variable in r创建一个新的日期变量,它与 r 中的原始日期变量在一周中的同一天、同一月和同一年
【发布时间】:2020-10-27 23:21:10
【问题描述】:

我需要从日期变量“casedates”创建一个新变量“controldates”。这个新变量将包含与案件日期在一周中的同一天、与案件日期在同一月和同一年的日期。例如,如果我的病例日期是 7 月的第 3 个星期三,我的控制日将是 7 月的第一个星期三、7 月的第二个星期三和 7 月的第 4 个星期三。此外,我想为每组创建的日期创建一个指标变量。我想在 r 中使用 dplyr 来做到这一点。

起始数据:

Casedate
 "01-03-2015"
 "08-27-2017"
 "10-23-2019"

这就是我想要的样子

Casedate          Controldate      Index
"01-03-2015"      "01-03-2015"       1
"01-03-2015"      "01-10-2015"       1
"01-03-2015"      "01-17-2015"       1
"01-03-2015"      "01-24-2015"       1
"01-03-2015"      "01-31-2015"       1
"08-12-2017"      "08-05-2017"       2
"08-12-2017"      "08-12-2017"       2
"08-12-2017"      "08-19-2017"       2
"08-12-2017"      "08-26-2017"       2
"10-23-2019"      "10-02-2019"       3
"10-23-2019"      "10-09-2019"       3
"10-23-2019"      "10-16-2019"       3
"10-23-2019"      "10-23-2019"       3
"10-23-2019"      "10-30-2019"       3

【问题讨论】:

  • 您的第二个日期输入是 "08-27-2017" ,但在输出中显示为 "08-12-2017"
  • 这是一个错字。感谢您引起我的注意。输入应该是 8-12-2017

标签: r date


【解决方案1】:

这是tidyverse 的选项。使用lubridate 将'Casedate' 转换为Date 类,然后使用map 循环遍历元素,在listunnestlist 列中创建sequence 日期

library(dplyr)
library(purrr)
library(lubridate)
df1 %>% 
   mutate(Index = row_number(), 
      Casedate = mdy(Casedate), 
     wd = wday(Casedate, label = TRUE), 
     Controldate = map2(floor_date(Casedate, 'month'), wd, ~ {
   x1 <- seq(.x, length.out = 7, by = '1 day')
    seq(x1[wday(x1, label = TRUE) == .y],
       ceiling_date(.x, 'month'), by = '7 day')})) %>% 
    unnest(c(Controldate)) %>%
    select(Casedate, Controldate, Index)

-输出

# A tibble: 14 x 3
#   Casedate   Controldate Index
#   <date>     <date>      <int>
# 1 2015-01-03 2015-01-03      1
# 2 2015-01-03 2015-01-10      1
# 3 2015-01-03 2015-01-17      1
# 4 2015-01-03 2015-01-24      1
# 5 2015-01-03 2015-01-31      1
# 6 2017-08-27 2017-08-06      2
# 7 2017-08-27 2017-08-13      2
# 8 2017-08-27 2017-08-20      2
# 9 2017-08-27 2017-08-27      2
#10 2019-10-23 2019-10-02      3
#11 2019-10-23 2019-10-09      3
#12 2019-10-23 2019-10-16      3
#13 2019-10-23 2019-10-23      3
#14 2019-10-23 2019-10-30      3

数据

df1 <- structure(list(Casedate = c("01-03-2015", "08-27-2017", "10-23-2019"
)), class = "data.frame", row.names = c(NA, -3L))

【讨论】:

  • 您需要c(Controldate) 还是只需要Controldateunnest 语句做它?
  • 感谢您的回复。我尝试在我的数据上运行它,它给出了错误: seq.int(from, by = by, length.out = length.out) 中的错误:'from' 必须是一个有限数另外:警告消息:所有格式解析失败。未找到任何格式。
  • 我在删除 Casedate=mdy(Casedate) 时让它运行。谢谢!
【解决方案2】:

由于一个月内最多只能在某个日期之前 4 周或之后 4 周(总共 9 个值),因此您可以使用一些序列一次性计算该范围。这应该避免显式循环每个值的需要。

计算值后,在一次扫描中将其子集到与原始值相同的月份。使用下面@akrun 的df1 示例数据:

d  <- as.Date(df1$Casedate, format="%m-%d-%Y")
r  <- rep(d, each=9)
o  <- r + (7 * -4:4)
i  <- rep(seq_along(d), each=9)
s  <- format(o, "%m") == format(r, "%m")

data.frame(
    Casedate = r,
    Controldate = o,
    Index = i
)[s,]

#     Casedate Controldate Index
#5  2015-01-03  2015-01-03     1
#6  2015-01-03  2015-01-10     1
#7  2015-01-03  2015-01-17     1
#8  2015-01-03  2015-01-24     1
#9  2015-01-03  2015-01-31     1
#11 2017-08-27  2017-08-06     2
#12 2017-08-27  2017-08-13     2
#13 2017-08-27  2017-08-20     2
#14 2017-08-27  2017-08-27     2
#20 2019-10-23  2019-10-02     3
#21 2019-10-23  2019-10-09     3
#22 2019-10-23  2019-10-16     3
#23 2019-10-23  2019-10-23     3
#24 2019-10-23  2019-10-30     3

如果你想保留数据集中的所有原始变量,这是一个简单的修复:

cbind(
  df1[i,],
  data.frame(Controldate = o, Index = i)
)[s,]

例如:

#      Casedate othvar1 othvar2 Controldate Index
#1.4 01-03-2015       a       B  2015-01-03     1
#1.5 01-03-2015       a       B  2015-01-10     1
#1.6 01-03-2015       a       B  2015-01-17     1
#1.7 01-03-2015       a       B  2015-01-24     1
#...

即使在中等大小的数据集(300K 行)上,生成序列运行(2 秒)和循环每个值(2 分钟)之间的时间差异也很明显:

顺序:

df1 <- df1[rep(1:3,each=1e5),,drop=FALSE]

system.time({
d  <- as.Date(df1$Casedate, format="%m-%d-%Y")
r  <- rep(d, each=9)
o  <- r + (7 * -4:4)
i  <- rep(seq_along(d), each=9)
s  <- format(o, "%m") == format(r, "%m")

data.frame(
    Casedate = r,
    Controldate = o,
    Index = i
)[s,]
})

#   user  system elapsed 
#  1.909   0.128   2.038 

循环:

library(dplyr)
library(purrr)
library(lubridate)

system.time({
df1 %>% 
   mutate(Index = row_number(), 
      Casedate = mdy(Casedate), 
     wd = wday(Casedate, label = TRUE), 
     Controldate = map2(floor_date(Casedate, 'month'), wd, ~ {
   x1 <- seq(.x, length.out = 7, by = '1 day')
    seq(x1[wday(x1, label = TRUE) == .y],
       ceiling_date(.x, 'month'), by = '7 day')})) %>% 
    unnest(Controldate) %>%
    select(Casedate, Controldate, Index)
})

#    user  system elapsed 
# 131.466   1.143 132.623

【讨论】:

  • 感谢您的回复。我想使用 dplyr 因为我有一个数据框,其中包含我想保留的 24 个其他变量。我宁愿不必将生成的数据框合并回原始数据框,以防我有来自不同参与者的重复案例日期。
  • @Sara - 这没什么大不了的 - 请参阅我的更新。此方法已经生成了一个行索引,您可以使用它来获取返回的所有可能已经在您的数据集中的其他变量。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-24
  • 1970-01-01
  • 2019-11-11
  • 1970-01-01
  • 2012-08-10
相关资源
最近更新 更多