3

我正在尝试从数字中提取日期。日期存储为 11 位个人 ID 号(日期-月-年)的前 6 位。不幸的是,此基于云的数据库 (REDCap) 输出被格式化为数字,因此当月前 9 天出生的人的前导零以 10 位 ID 号结束,而不是 11 位数字。我设法提取了与日期相对应的 6 位或 5 位数字,即 311230 表示 1930 年 12 月 31 日,或 11230 表示 1930 年 12 月 1 日。我最终遇到了两个我无法解决的问题。

假设我们使用以下数字:

dato <- c(311230, 311245, 311267, 311268, 310169, 201104, 51230, 51269, 51204)

我将这些转换为字符串,然后应用 as.Date() 函数:

datostr <- as.character(dato)
datofinal <- as.Date(datostr, "%d%m%y")
datofinal

我遇到的问题是:

  • 五位数字(例如 11230)报告为 NA。
  • 六位数字被识别,但在 1.1.1969 之前出生的数字被报告加上 100 年,即 010160 被转换为 2060.01.01

我相信这对于那些更了解 R 的人来说一定很容易,但是,我很难解决这个问题。任何帮助是极大的赞赏。

问候比约恩

4

3 回答 3

5

如果你的 5 位数字真的只需要补零,那么

dato_s <- sprintf("%06d", dato)
dato_s
# [1] "311230" "311245" "311267" "311268" "310169" "201104" "051230" "051269" "051204"

从那里,您关于"dates before 1969"?strptime的问题,看看'%y'模式:

 '%y' Year without century (00-99).  On input, values 00 to 68 are
      prefixed by 20 and 69 to 99 by 19 - that is the behaviour
      specified by the 2018 POSIX standard, but it does also say
      'it is expected that in a future version the default century
      inferred from a 2-digit year will change'.

因此,如果您有特定的备用年份,则需要在发送到之前添加世纪as.Date(使用strptime-patterns)。

dato_d <- as.Date(gsub("([0-4][0-9])$", "20\\1",
                       gsub("([5-9][0-9])$", "19\\1", dato_s)),
                  format = "%d%m%Y")
dato_d
# [1] "2030-12-31" "2045-12-31" "1967-12-31" "1968-12-31" "1969-01-31" "2004-11-20"
# [7] "2030-12-05" "1969-12-05" "2004-12-05"

在这种情况下,我假设 50-99 将是 1900,其他都是 2000。如果您需要 40 或 30,请随意调整模式:将数字添加到第二个模式(例如,[3-9])并从第一个模式中删除(例如,[0-2]),确保所有十年都包含在一个模式中,而不是“两者都”而不是“两者”。

借用艾伦的回答,我喜欢这个假设now()(因为你确实提到了“出生于”)。没有lubridate,试试这个:

dato_s <- sprintf("%06d", dato)
dato_d <- as.Date(dato_s, format = "%d%m%y")
dato_d[ dato_d > Sys.Date() ] <-
  as.Date(sub("([0-9]{2})$", "19\\1", dato_s[ dato_d > Sys.Date() ]), format = "%d%m%Y")
dato_d
# [1] "1930-12-31" "1945-12-31" "1967-12-31" "1968-12-31" "1969-01-31" "2004-11-20"
# [7] "1930-12-05" "1969-12-05" "2004-12-05"
于 2020-06-29T14:56:10.263 回答
4

您可以使用 使这更容易一点lubridate,并注意没有人可以拥有当前时间未来的出生日期:

library(lubridate)

dato <- dmy(sprintf("%06d", dato))
dato[dato > now()] <- dato[dato > now()] - years(100)

dato
#> [1] "1930-12-31" "1945-12-31" "1967-12-31" "1968-12-31" "1969-01-31"
#> [6] "2004-11-20" "1930-12-05" "1969-12-05" "2004-12-05"

当然,如果没有进一步的信息,这种方法(任何其他方法也不会)能够挑选出 100 岁以上的人的边缘情况。这可能很容易从上下文中确定。

reprex 包(v0.3.0)于 2020 年 6 月 29 日创建

于 2020-06-29T15:00:35.810 回答
1

将五位数的“数字”转换为六位数很简单:x <- stringr::str_pad(x, 6, pad="0")或类似的方法可以解决问题。

您多年来的问题是重新审视千年虫。您必须咨询编译您的数据的人,以了解他们使用了哪些假设。

我怀疑 31Dec1970 或之前的所有日期都会受到影响,而不仅仅是 01Jan1960 之前的日期。这是因为as.Date在决定如何处理两位数年份时使用默认原点 01Jan1970。所以你的解决方案是在你的转换中选择一个合适的来源来修复这个数据集。类似的东西d <- as.Date(x, origin="1900-01-01")。然后开始使用四位数的年份!;)

于 2020-06-29T14:57:56.923 回答