lubridate将小数转换为月份

时间:2018-03-27 10:24:10

标签: r decimal duration lubridate

我使用age.first.union通过从出生日期lubridate中减去婚礼日期wdow来估算变量wdob作为时差。我得到了以下数字向量

head(wm$age.first.union, 3)
[1] 15.43014 12.67123 17.34247

我希望将小数转换为几个月(也可能是几天,但这是一个小细节),因此第一个值将是15年零5个月。我所做的是创建一系列新变量,然后执行一些计算。为了获得月数,首先,我复制并截断了age.first.union变量。然后我估计了两者之间的差异,只得到小数部分,然后使用比例(例如0.43 : 10 = x : 12)得到月份。

我查看了lubridate文档,但我找不到这方面的内容。我尝试了以下

years(floor(dseconds(15.43014)))

但我只有这些年

[1] "15y 0m 0d 0H 0M 0S"

一个想法是以秒为单位获得持续时间

seconds(floor(dyears(15.43014)))
[1] "486604895S"

但接下来的挑战是几个月有不同的长度。即使近似年数= 365天,月数= 30天也会更完美,但除了冗长的计算之外,我不知道如何做到这一点。

最后一个想法是使用本文开头所述的计算年份和月份,然后使用类似于make_date的东西将两个变量合并到最后一个变量中(但它看起来像一个make_duration似乎尚不存在。)

对我来说整个过程看起来很麻烦,任何人都有不同的看法?

非常感谢

莫罗

2 个答案:

答案 0 :(得分:0)

虽然decimal_date提供了将小数日期转换为DMY 日期的函数30.42,但您似乎正在处理持续时间。所以这不会起作用。

但是,您可以非常轻松地定义自定义函数以提取整数年,月和小数日(基于常规年中每月平均age <- c(15.43014 12.67123 17.34247) f <- function(x) { year <- floor(x); month <- floor((x - year) * 12); day <- ((x - year) * 12 - month) * 30.42; return(sprintf("%i years, %i months, %3.2f days", year, month, day)) } lapply(age, f); #[[1]] #[1] "15 years, 5 months, 4.92 days" # #[[2]] #[1] "12 years, 8 months, 1.67 days" # #[[3]] #[1] "17 years, 4 months, 3.34 days" 天):

f

更新

如果您想要返回整数年,月和小数日,可以将f <- function(x) { year <- floor(x); month <- floor((x - year) * 12); day <- ((x - year) * 12 - month) * 30.42; return(list(year = year, month = month, day = day)) } 定义为

sapply(age, f);
#      [,1]     [,2]     [,3]
#year  15       12       17
#month 5        8        4
#day   4.918306 1.665799 3.335249

给你,例如

$link

答案 1 :(得分:0)

我们可以定义自己的ym S3类来表示年/月对象。在这里,我们定义了几个ym方法以及多年和几个月的提取器函数。 as.data.frame.ym方法是部分实现。我们将一个月定义为一年的1/12。

as.ym <- function(x, ...) structure(x, class = "ym")
as.data.frame.ym <- function(x, ...) 
  structure(list(x), row.names = seq_along(x), class = "data.frame")
years.ym <- as.integer
months.ym <- function(x) 12 * as.numeric(x) %% 1
format.ym <- function(x, ...) paste0(years.ym(x), "Y ", round(months.ym(x)), "M")
print.ym <- function(x, ...) print(format(x), ...)

# test

x <- c(15.43014, 12.67123, 17.34247) # test input

xx <- as.ym(x)
xx
## [1] "15Y 5M" "12Y 8M" "17Y 4M"

DF <- data.frame(x, xx)
DF
         x     xx
1 15.43014 15Y 5M
2 12.67123 12Y 8M
3 17.34247 17Y 4M

years.ym(xx)
## [1] 15 12 17

months.ym(xx)
## [1] 5.16168 8.05476 4.10964

class(xx)
## [1] "ym"

为了将此延伸到包含天数,我们假设一年中有365.25天,并且我们再次使用一年中的12个月。我们为此创建了一个ymd S3类。

as.ymd <- function(x, ...) structure(x, class = "ymd")
as.data.frame.ymd <- function(x, ...) 
  structure(list(x), row.names = seq_along(x), class = "data.frame")
years.ymd <- as.integer
months.ymd <- function(x) as.integer(12 * as.numeric(x) %% 1)
days.ymd <- function(x) (365.25 * as.numeric(x)) %% (365.25 / 12)
format.ymd <- function(x, ...) 
 paste0(years.ymd(x), "Y ", as.integer(months.ymd(x)), "M ", round(days.ymd(x), 1), "D")
print.ymd <- function(x, ...) print(format(x), ...)

xx <- as.ymd(x)
xx
## [1] "15Y 5M 4.9D" "12Y 8M 1.7D" "17Y 4M 3.3D"

DF <- data.frame(x, xx)
DF
         x          xx
1 15.43014 15Y 5M 4.9D
2 12.67123 12Y 8M 1.7D
3 17.34247 17Y 4M 3.3D

years.ymd(xx)
## [1] 15 12 17

months.ymd(xx)
## [1] 5 8 4

days.ymd(xx)
## [1] 4.921135 1.666758 3.337167

class(xx)
## [1] "ymd"