R:应用函数中最佳方式as.POSIXct()

时间:2017-08-22 12:14:14

标签: r date apply posixct

我正在尝试设置一个新变量,该变量包含已知日期和给定年份结束之间的差异(天数)。下面的虚拟数据:

> Date.event <- as.POSIXct(c("12/2/2000","8/2/2001"), format = "%d/%m/%Y", tz = "Europe/London")
> Year = c(2000,2001)
> Dates.test <- data.frame(Date.event,Year)
> Dates.test
  Date.event Year
1 2000-02-12 2000
2 2001-02-08 2001

我已尝试应用函数来实现此目的,但它返回错误

> Time.dif.fun <- function(x) {
+ as.numeric(as.POSIXct(sprintf('31/12/%s', s= x['Year']),format = "%d/%m/%Y", tz = "Europe/London") - x['Date.event'])
+ }
> Dates.test$Time.dif <- apply(
+ Dates.test, 1, Time.dif.fun
+ )

 Error in unclass(e1) - e2 : non-numeric argument to binary operator 

似乎apply()不喜欢as.POSIXct(),因为测试只导出年终日期的函数版本,它将以“978220800”形式返回为数字(例如,结束2000年)。有没有办法解决?对于真实数据,函数有点复杂,包括使用不同变量的条件实例,有时也会引用前面的行,如果不应用这将很难做到。

3 个答案:

答案 0 :(得分:1)

以下是一些替代方案:

1)您的代码可以使用这些更改。我们考虑了s,不是因为它是必要的,而是因为由于它的长度,下面的行变得非常难以阅读。请注意,如果x是数据框,那么x["Year"]也是如此,但x[["Year"]]x$Year的向量。由于操作都是矢量化的,因此我们不需要apply

虽然我们没有进行此更改,但将s定义为s <- paste0(x$Year, "-12-31")会更容易一些,在这种情况下,由于使用了默认格式,我们可以省略以下行中的format参数。

Time.dif.fun <- function(x) {
  s <- sprintf('31/12/%s', x[['Year']])
  as.numeric(as.POSIXct(s, format = "%d/%m/%Y", tz = "Europe/London") -x[['Date.event']])
}
Time.dif.fun(Dates.test)
## [1] 323 326

2)转换为POSIXlt,将年,月和日设置为年末并减去。请注意,年份组件使用自1900年以来的年份,mon组件使用Jan = 0,Feb = 1,...,Dec = 11.有关这些组件和其他组件的详细信息,请参阅?as.POSIXlt

lt <- as.POSIXlt(Dates.test$Date.event)
lt$year <- Dates.test$Year - 1900
lt$mon <- 11
lt$mday <- 31
as.numeric(lt - Dates.test$Date.event)
## [1] 323 326

3)另一种可能性是:

with(Dates.test, as.numeric(as.Date(paste0(Year, "-12-31")) - as.Date(Date.event)))
## [1] 323 326

答案 1 :(得分:0)

您可以使用difftime功能:

Dates.test$diff_days <- difftime(as.POSIXct(paste0(Dates.test[,2],"-12-31"),format = "%Y-%m-%d", tz = "Europe/London"),Dates.test[,1],unit="days")

答案 2 :(得分:0)

您可以使用ISOdate来构建年终日期,使用difftime(... units='days')来获取截至年底的日期。

来自?difftime

  

“difftime”对象有限运算:它们可以   加上或减去,乘以或除以数字向量。

如果你想做的不仅仅是有限的算术,只需强迫as.numeric(),但你必须坚持你指定的任何单位。

按照惯例,您可能希望使用下一年的开始(新年前夕的午夜)作为该年度的终点。例如:

Dates.test <- data.frame(
  Date.event = as.POSIXct(c("12/2/2000","8/2/2001"), 
                          format = "%d/%m/%Y", tz = "Europe/London")
)
# use data.table::year() to get the year of a date
year <- function(x) as.POSIXlt(x)$year + 1900L
Dates.test$Date.end <- ISOdate(year(Dates.test$Date.event)+1,1,1)

# if you don't want class 'difftime', wrap it in as.numeric(), as in:
Dates.test$Date.diff <- as.numeric(
                             difftime(Dates.test$Date.end, 
                                      Dates.test$Date.event, 
                                      units='days')
                        )
Dates.test
#   Date.event            Date.end Date.diff
# 1 2000-02-12 2001-01-01 12:00:00     324.5
# 2 2001-02-08 2002-01-01 12:00:00     327.5

apply()系列基本上是一种干净的for循环方式,您应该努力寻找更有效的矢量化解决方案。