ifelse с датами в трубе dplyr - PullRequest
0 голосов
/ 20 сентября 2018

Предположим, у меня есть эти данные:

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 вместо ifelse с датами, но я бы хотел остаться в пределах обратного хода.


Обновление 1

Здесь столбец dur обозначает ожидаемый результат:

| 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"))            |


Обновление 2

Я следовалнекоторые из предложений.Следующее:

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)
                       )
         )

производит:

         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)

, что явно не то, что я хочу.


Обновление 3 (решено)!)

Благодаря @ jdobres Мне пришлось использовать pmax вместо max.Причина ускользает от меня, но документация гласит: pmax и pmin также будут работать с классифицированными объектами S3 или S4 с соответствующими методами для сравнения, is.na и rep (если необходима переработка аргументов) .Я подозреваю, что объекты S4 имеют отношение к этому.

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)
                       )
         )

Производит:

         end      start                      dur
1 9999-12-31 2012-02-27 207100800s (~6.56 years)
2 9999-12-31 2016-02-16  81820800s (~2.59 years)
3 2017-09-25 2009-01-05 180921600s (~5.73 years)
4 9999-12-31 2007-10-15 212025600s (~6.72 years)
5 9999-12-31 2003-02-18 212025600s (~6.72 years)
6 9999-12-31 2006-07-31 212025600s (~6.72 years)

Ответы [ 2 ]

0 голосов
/ 20 сентября 2018

Как только вы преобразуете свои строки даты в данные Date с помощью ymd или as.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)
                       )
                    )
0 голосов
/ 20 сентября 2018

Я пытался выполнить мутацию, как и вы, после использования 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() снова в функции.Я заметил это раньше, и я не уверен, почему.

...