dplyr管道中带有日期的ifelse

时间:2018-09-20 03:49:09

标签: r date dplyr lubridate

假设我有这些数据:

pandas

我想创建第三个变量df <- structure(list(end = structure(c(2932896, 2932896, 17434, 2932896, 2932896, 2932896), class = "Date"), start = structure(c(15397, 16847, 14249, 13801, 12101, 13360), class = "Date")), class = "data.frame", row.names = c(NA, -6L)) > df end start 1 9999-12-31 2012-02-27 2 9999-12-31 2016-02-16 3 2017-09-25 2009-01-05 4 9999-12-31 2007-10-15 5 9999-12-31 2003-02-18 6 9999-12-31 2006-07-31 ,条件是某些语句:

dur

会产生错误:

library(dplyr)
library(lubridate)

df %>%
  mutate(dur = if_else(end == "9999-12-31",
                       as.duration(today() - max("2012-01-01", start)),
                       as.duration(max(start, "2012-01-01") - end)
                       )
         )

我知道有人建议在日期中使用Error in mutate_impl(.data, dots) : Evaluation error: non-numeric argument to binary operator. 而不是DT,但我想保留在tidyverse中。


更新1

在这里,列ifelse表示预期的输出:

dur


更新2

我遵循了一些建议。以下:

| end           | start         | dur                       | code                                              |
|------------   |------------   |-------------------------- |-------------------------------------------------- |
| 9999-12-31    | 2012-02-27    | 207100800s (~6.56 years)  | as.duration(today()-ymd("2012-02-27"))            |
| 9999-12-31    | 2016-02-16    | 81820800s (~2.59 years)   | as.duration(today()-ymd("2016-02-16"))            |
| 2017-09-25    | 2009-01-05    | 180921600s (~5.73 years)  | as.duration(ymd("2017-09-25")-ymd("2012-01-01"))  |
| 9999-12-31    | 2007-10-15    | 212025600s (~6.72 years)  | as.duration(today()-ymd("2012-01-01"))            |
| 9999-12-31    | 2003-02-18    | 212025600s (~6.72 years)  | as.duration(today()-ymd("2012-01-01"))            |
| 9999-12-31    | 2006-07-31    | 212025600s (~6.72 years)  | as.duration(today()-ymd("2012-01-01"))            |

产生:

df %>%
  mutate(dur = if_else(end == ymd("9999-12-31"),
                       as.duration(today() - max(ymd("2012-01-01"), start)),
                       as.duration(max(start, ymd("2012-01-01")) - end)
                       )
         )

这显然不是我想要的。


更新3(已解决!)

由于@jdobres,我不得不使用 end start dur 1 9999-12-31 2012-02-27 81820800s (~2.59 years) 2 9999-12-31 2016-02-16 81820800s (~2.59 years) 3 2017-09-25 2009-01-05 50716800s (~1.61 years) 4 9999-12-31 2007-10-15 81820800s (~2.59 years) 5 9999-12-31 2003-02-18 81820800s (~2.59 years) 6 9999-12-31 2006-07-31 81820800s (~2.59 years) 而不是pmax。原因逃脱了我,但文档说: pmax和pmin也可以通过适当的比较方法is.na和rep(如果需要循环使用参数)在分类的S3或S4对象上工作。。我怀疑S4对象与此有关。

max

产生:

df %>%
  mutate(dur = if_else(end == ymd("9999-12-31"),
                       as.duration(today() - pmax(ymd("2012-01-01"), start)),
                       as.duration(pmax(start, ymd("2012-01-01")) - end)
                       )
         )

2 个答案:

答案 0 :(得分:2)

使用ymdas.Date将日期字符串转换为Date数据后,就可以使用pmax获取两个持续时间中的较大者。 pmax为您提供了元素数量相同的向量之间的平行最大值。例如:

 pmax(1:10, rep(5, 10))

 [1]  5  5  5  5  5  6  7  8  9 10

代码如下:

df %>%
  mutate(dur = if_else(end == ymd("9999-12-31"),
                       as.duration(today() - pmax(ymd("2012-01-01"), start)),
                       as.duration(pmax(start, ymd("2012-01-01")) - end)
                       )
                    )

答案 1 :(得分:1)

在您输入的字符日期上使用lubridate::ymd()之后,我尝试像您一样进行突变,但是max()并未逐行进行比较,但是抓住了所有初始值的最大值-也许有人可以解释为什么?

我最终申请了。

library(dplyr)
library(lubridate)

df %>%
  mutate(dur =
           apply(tbl_df(df), 1, function(x){
             print(x)

             ifelse(
               x["end"] == ymd("9999-12-31"),

               interval(today(), max(ymd("2012-01-01"), ymd(x["start"]))) %>%
                 as.duration() %>%
                 as.numeric("years"),

               interval(max(x["start"], ymd("2012-01-01")), ymd(x["end"])) %>%
                 as.duration() %>%
                 as.numeric("years")
             )

           }))

#          end      start       dur
# 1 9999-12-31 2012-02-27 -6.562628
# 2 9999-12-31 2016-02-16 -2.592745
# 3 2017-09-25 2009-01-05  8.720055
# 4 9999-12-31 2007-10-15 -6.718686
# 5 9999-12-31 2003-02-18 -6.718686
# 6 9999-12-31 2006-07-31 -6.718686

即使开始和结束值已经是日期格式,我仍需要在函数中再次使用ymd()。我以前已经注意到了这一点,但不确定为什么。