使用lubridate计算年份差异?

43

我想使用lubridate来计算一个人的年龄,根据他们的出生日期和今天的日期。目前我的代码是这样的:

library(lubridate)
today<-mdy(08312015)
dob<-mdy(09071982)
today-dob

它会给我他们的年龄(以天为单位)。


按照365.25除,不够准确吗? - lenz
1
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - phiver
是的,但 (今天-生日)/365.25 给出的结果是 时间差为32.98015天 而不是年。 - Ignacio
6
你所看到的只是一个标签。我通常发现更容易改变结果的类别:as.numeric((today-dob)/365.25)。如果想要略微提高精度,可以除以365.2425。 - Benjamin
2
请注意,使用 today - dob 不是 lubridate 的正确方法,而是使用基本的 R 功能(difftime)。请参考我的答案,了解 lubridate 的方法。 - Paul Hiemstra
6个回答

68

这是我会采用的lubridate方法:

interval(dob, today) / years(1)

产生答案为 32 年。

请注意,该函数会抱怨它不能表达年份的余数部分,这是因为年份不是一个固定的概念,即在闰年中为366天,在非闰年中为365天。您可以得到更详细的答案,涉及到周数和天数:

interval_period = interval(dob, today)
full_year = interval_period %/% years(1)
remaining_weeks = interval_period %% years(1) %/% weeks(1)
remaining_days = interval_period %% years(1) %% weeks(1) %/% days(1)
sprintf('Your age is %d years, %d weeks and %d days', full_year, remaining_weeks, remaining_days)
# [1] "Your age is 32 years, 51 weeks and 1 days"

请注意,我使用%/%来表示除法,%%表示取模运算,以获得减去整年/整周后剩余的周数/天数。


2
谢谢,这正是我想要的。请注意,new_interval已被弃用,请改用interval - dpel
请注意,'new_interval'已被弃用,请改用'interval'。自版本'1.5.0'起已弃用。 - amonk
新区间(dob,today)和dob-today以及as.period(today-dob,unit="years")之间有什么区别? - skan
1
自v1.5.0版本起,new_interval已被弃用,现在只需使用interval - MS Berends

13

这是一个老问题,但我仍然缺少以下简洁的方法。(Tidyverse 仅对 %>% 运算符是必需的。)

library(tidyverse)
library(lubridate)

today<-mdy(08312015)
dob<-mdy(09071982)

interval(dob, today) %>%
  as.numeric('years')

# 32.98015 - you have to decide how to deal with the fraction of a year

这真是太棒了。您能否解释一下 as.numeric("years") 如何针对 interval() 的输出进行工作? - Emman

6
as.duration(interval(dob,today)) %/% as.duration(years(1))

应该能够无错误地完成工作。

2
感谢您提供这段代码片段,它可能会立即提供一些帮助。通过展示为什么这是一个好的解决方案,适当的解释将极大地提高其教育价值,并使其对未来有类似但不完全相同的问题的读者更有用。请编辑您的答案以添加解释,并指出适用的限制和假设。 - basvk

4
as.period(today - dob, unit = "years")

这将会显示一个消息,说明它只是一个估计值,因为它没有考虑确切的开始日期和结束日期。


3
另一种 Tidyverse 方法(使用最少的代码)是:
library(tidyverse)
library(lubridate)

today<-mdy(08312015)
dob<-mdy(09071982)

dob %--% today / ddays(365.25)


dob %--% today / ddays(365)) 的结果是 33.00274,这是不准确的(应该是32岁,52周和1天)。而 dob %--% today / years(1) 的结果是 32.98082,这是准确的(而且代码更短 :-) )。此外,你的示例中有一个多余的括号。 - Jeff Parker
谢谢你的括号,我已经去掉了,所以这取决于你如何定义一年:在闰年中,你会有366天;在普通年份中,你会有365.25天。我加上了0.25,这样我们得到了相同的答案。不过我确实喜欢年份的方法...是的,我想,从技术上讲更短 :) - James

0

另一个答案,速度更快。请参阅以下速度测试

as.numeric(today - dob) / 365.25

比较所有答案

library(dplyr)
library(lubridate)

today<-mdy(08312015)
dob<-mdy(09071982)

interval(dob, today) / years(1)
> 32.98082

as.duration(interval(dob,today)) %/% as.duration(years(1))
> 32

interval(dob, today) %>% as.numeric('years')
> 32.98015

dob %--% today / ddays(365.25)
> 32.98015

as.numeric(today - dob) / 365.25
> 32.98015

我不确定哪个更正确:32.98082还是32.98015。请参见https://dev59.com/s1wY5IYBdhLWcg3ws5kF#32313487

速度测试

microbenchmark::microbenchmark(
  interval(dob, today) / years(1),
  as.duration(interval(dob,today)) %/% as.duration(years(1)),
  interval(dob, today) %>% as.numeric('years'),
  dob %--% today / ddays(365.25),
  as.numeric(today - dob) / 365.25
)

> Unit: microseconds
>                                                       expr      min        lq       mean    median       uq      max neval
>                              interval(dob, today)/years(1) 1913.601 1996.1510 2172.96001 2059.1005 2102.851 6037.201   100
>  as.duration(interval(dob, today))%/%as.duration(years(1))  749.700  799.1010  912.30394  823.1510  863.751 5078.601   100
>               interval(dob, today) %>% as.numeric("years")  439.701  464.0510  485.31708  480.3010  501.101  591.000   100
>                               dob %--% today/ddays(365.25)  394.501  427.5510  450.37502  443.7010  463.301  620.601   100
>                             as.numeric(today - dob)/365.25   17.400   25.9005   30.66293   32.7515   36.151   52.700   100

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