是否有其他方法可以替换dplyr下的以下代码,以避免显式循环和数据名称来实现以下目的?
如果满足当前supp_date小于先前supp_date +数位板的条件,这将创建一个调整日期。
样本数据:(这是带有else
格的新样本数据。)
test <- read.table(text =
"supp_date tablet
2017-07-19 30
2017-08-07 30
2017-09-08 30
2017-10-30 30
2017-11-08 30
2017-12-07 30", header = T)
R代码:
test$supp_date <- as.Date(test$supp_date, "%Y-%m-%d")
test$adj_fill_dt <- as.Date(NA, "%Y-%m-%d")
test$adj_fill_dt[1] <- test$supp_date[1]
for(i in 2:6) {
if (test[i, "supp_date"] < test[i-1, "adj_fill_dt"] + test[i-1, "tablet"]) {
test[i, "adj_fill_dt"] <- test[i-1, "adj_fill_dt"] + test[i-1, "tablet"]
} else {
test[i, "adj_fill_dt"] <- test[i, "supp_date"]
}
}
发件人:
supp_date tablet
2017-07-19 30
2017-08-07 30
2017-09-08 30
2017-10-30 30
2017-11-08 30
2017-12-07 30
收件人:
supp_date tablet adj_fill_dt
2017-07-19 30 2017-07-19
2017-08-07 30 2017-08-18
2017-09-08 30 2017-09-17
2017-10-30 30 2017-10-30
2017-11-08 30 2017-11-29
2017-12-07 30 2017-12-29
答案 0 :(得分:2)
我们可以使用accumulate
library(tidyverse)
df %>%
mutate(tmp = as.numeric(supp_date),
adj_fill_dt = as.Date(accumulate(tmp[-1], ~
pmax(.x + tablet[1], .y), .init = tmp[1]),
origin = '1970-01-01'),
tmp = NULL)
# supp_date tablet adj_fill_dt
#1 2017-07-19 30 2017-07-19
#2 2017-08-07 30 2017-08-18
#3 2017-09-08 30 2017-09-17
#4 2017-10-30 30 2017-10-30
#5 2017-11-08 30 2017-11-29
#6 2017-12-07 30 2017-12-29
或者使用base R
的{{1}}
Reduce
v1 <- as.numeric(df$supp_date)
as.Date(Reduce(function(u, v) pmax(u + 30, v), v1[-1],
init = v1[1], accumulate = TRUE), origin = '1970-01-01')
#[1] "2017-07-19" "2017-08-18" "2017-09-17" "2017-10-30" "2017-11-29"
#[6] "2017-12-29"
答案 1 :(得分:1)
以下内容再现了您的预期输出
library(tidyverse)
df %>%
mutate(
supp_date = as.Date(supp_date, format = "%Y-%m-%d"),
adj_fill_dt = if_else(
supp_date < supp_date[1] + cumsum(tablet),
lag(supp_date[1] + cumsum(tablet), default = supp_date[1]),
supp_date))
# supp_date tablet adj_fill_dt
#1 2017-07-19 30 2017-07-19
#2 2017-08-07 30 2017-08-18
#3 2017-09-08 30 2017-09-17
#4 2017-10-11 30 2017-10-17
#5 2017-11-08 30 2017-11-16
#6 2017-12-07 30 2017-12-16
请注意,这需要对更大的样本数据进行彻底的测试;根据您提供的示例数据,我们绝不会将其纳入else
(或您的情况if_else
)条件的if {...} else {...}
部分中。
这里的关键是要认识到在if
条件下的递归关系可以重写为supp_date[1] + cumsum(tablet)
。
df <- read.table(text =
"supp_date tablet
2017-07-19 30
2017-08-07 30
2017-09-08 30
2017-10-11 30
2017-11-08 30
2017-12-07 30", header = T)
下面的代码重现了两个示例的输出
df %>%
mutate(
supp_date = as.Date(supp_date, format = "%Y-%m-%d"),
grp = cumsum(!(supp_date < lag(supp_date[1] + cumsum(tablet), default = supp_date[1])))) %>%
group_by(grp) %>%
mutate(adj_fill_dt = lag(supp_date[1] + cumsum(tablet), default = supp_date[1]))
## A tibble: 6 x 4
## Groups: grp [2]
# supp_date tablet grp adj_fill_dt
# <date> <int> <int> <date>
#1 2017-07-19 30 1 2017-07-19
#2 2017-08-07 30 1 2017-08-18
#3 2017-09-08 30 1 2017-09-17
#4 2017-10-30 30 2 2017-10-30
#5 2017-11-08 30 2 2017-11-29
#6 2017-12-07 30 2 2017-12-29