使用lubridate函数和mutate计算年龄

6
我想根据出生日期计算年龄。
如果我使用lubridate,只需按以下方式运行,如 Efficient and accurate age calculation (in years, months, or weeks) in R given birth date and an arbitrary dateas.period(new_interval(start = birthdate, end = givendate))$year 但是,当我尝试在dplyr中使用mutate创建新变量时,遇到了错误。
library(dplyr); library(lubridate)

birthdate <- ymd(c(NA, "1978-12-31", "1979-01-01", "1962-12-30"))
givendate <- ymd(c(NA, "2015-12-31", "2015-12-31", NA))

df <- data.frame(
    birthdate = birthdate,
    givendate = givendate)

以下内容可以使用,但它会提供所有日期和时间值,即年、月、日、小时、分钟和秒。
df<-df %>% mutate(age=as.period(interval(start = birthdate, end = givendate)))

# df
#    birthdate  givendate                  age
# 1       <NA>       <NA>                 <NA>
# 2 1978-12-31 2015-12-31   37y 0m 0d 0H 0M 0S
# 3 1979-01-01 2015-12-31 36y 11m 30d 0H 0M 0S
# 4 1962-12-30       <NA>                 <NA>

以下方法无效:
df<-df %>% 
       mutate(age=as.period(interval(start = birthdate, end = givendate))$year)

出现错误:

在 mutate_impl(.data, dots) 中出现错误:无效的下标类型 'closure'

我认为可能是由于缺失值导致的。因此,我尝试了以下操作:

df<-df %>% 
   mutate(age=as.period(interval(start = birthdate, end = givendate))) %>% 
   mutate(age=if_else(!is.na(age),age$year,age))

它也给出了一个错误:
“mutate_impl(.data, dots)中的错误:找不到'age'对象”

@akrun 当我应用第一个mutate时,数据集中已经有了age变量。我对年龄应用$year,因为我认为我可以提取该期间的年份 - HNSKD
'age' 是一个具有 'period' 类的变量,可能不被 mutate 函数支持。 - akrun
3个回答

7
lubridate 中,
  • Period 是一个 S4 类,其中有一个名为 "year" 的 slot
  • year 是一个 S3 类对象,其中包含一种方法来从 period 对象中提取 year slot。

请参见https://github.com/hadley/lubridate/blob/master/R/accessors-year.r)中的访问器函数来提取年份组件。

因此,以下代码将起作用:

df %>% mutate(age = year(as.period(interval(start = birthdate, end = givendate))))

3
我们可以使用lubridate中的year函数来获取两个日期之间的年份差异。
library(dplyr); library(lubridate)
df %>% mutate(age = year(givendate) - year(birthdate))

#   birthdate  givendate age
#1       <NA>       <NA>  NA
#2 1978-12-31 2015-12-31  37
#3 1979-01-01 2015-12-31  36
#4 1962-12-30       <NA>  NA

5
仅使用年份计算年龄并不准确。如果一个人的出生日期是1978-12-31,给定日期是2015-12-30,那么他仍然是36岁,因为他的生日还没有到。 - HNSKD
1
@HNSKD 噢..是的!因为 year 只提取日期中的年份部分。最直接的方法就像 @Spacedman 建议的那样,使用 as.period(interval(start = df$birthdate, end = df$givendate))$year - Ronak Shah

1
我们可以使用do
df %>%
   mutate(age=as.period(interval(start = birthdate, end = givendate))) %>%
   do(data.frame(.[setdiff(names(.), "age")], 
       age = ifelse(!is.na(.$age), .$age$year, .$age)))
#    birthdate  givendate age
#1       <NA>       <NA>  NA
#2 1978-12-31 2015-12-31  37
#3 1979-01-01 2015-12-31  36
#4 1962-12-30       <NA>  NA

作为as.period是由period类提供的,我们可能需要使用S4方法来提取它。
df %>% 
    mutate(age=as.period(interval(start = birthdate, end = givendate))) %>%
   .$age %>%
   .@year %>%
    mutate(df, age = .)
#  birthdate  givendate age
#1       <NA>       <NA>  NA
#2 1978-12-31 2015-12-31  37
#3 1979-01-01 2015-12-31  36
#4 1962-12-30       <NA>  NA

这段代码简短而精炼,但我该如何理解它? - HNSKD
@HNSKD 谢谢,我也添加了一个使用 mutate 的版本。 - akrun
9
非dplyr版本更易理解,可以简单地写成:df$age=as.period(interval(start = df$birthdate, end = df$givendate))$year - Spacedman
5
如果必须使用dplyr,因为需要使用hadleyverse的话,使用lubridate的year函数有什么问题吗?使用@访问器被认为是有害的。可以使用以下代码将年龄计算到数据框中:df %>% mutate(age = year(as.period(interval(start = birthdate, end = givendate)))) - Spacedman
@akrun 不是我的操作。 - Spacedman
@Spacedman 我知道你是个很棒的人! :-) - akrun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接