ifelse 与 dplyr 管道中的日期
ifelse with dates in dplyr pipe
假设我有这些数据:
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
,但我想留在 tidyverse 中。
更新 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)
在对您输入的字符日期使用 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()
。我以前注意到过这一点,但我不确定为什么。
一旦您使用 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)
)
)
假设我有这些数据:
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
,但我想留在 tidyverse 中。
更新 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)
在对您输入的字符日期使用 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()
。我以前注意到过这一点,但我不确定为什么。
一旦您使用 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)
)
)