我有一组客户,他们的日常活动日志,以及他们的帐户是否有问题。客户在作为客户期间可以多次在其帐户上提出问题,并且问题可能会持续提出多天。我想计算出每个帐户提出问题的持续时间。日期可以从任何地方开始,问题可能随时发生,在下面的示例中保存为 TRUE=1 和 FALSE=0。
一些示例数据:
df <- data.frame(customer= c('AB','AB','AB', 'AB','AB','BC','BC','BC','CD','CD','CD','CD'), date=as.Date(c("11/09/2000","12/09/2000","13/09/2000","14/09/2000","15/09/2000","13/09/2000","14/09/2000","15/09/2000","23/05/2001","24/05/2001","25/05/2001", "26/05/2001"), "%d/%m/%Y"),
issue=c(0,1,1,1,1,0,0,1,1,0,1,1))
我尝试制作一个索引计数器,以及此线程中发现的一些其他变体:计算 R 中上次事件以来的天数,但它不会计算连续天数(即 AB 不断显示,每个事件的持续时间为 1)天而不是2,3,4),如下图:
顾客 | 日期 | 问题 | 持续时间 |
---|---|---|---|
AB | 2000-09-11 | 0 | 0 |
AB | 2000-09-12 | 1 | 1 |
AB | 2000-09-13 | 1 | 1 |
AB | 2000-09-14 | 1 | 1 |
AB | 2000-09-15 | 1 | 1 |
我需要的输出类似于:
客户 | 日期 | 问题 | 持续时间 |
---|---|---|---|
AB | 2000-09-11 | 0 | 0 |
AB | 2000-09-12 | 1 | 1 |
AB | 2000-09-13 | 1 | 2 |
AB | 2000-09-14 | 1 | 3 |
AB | 2000-09-15 | 1 | 4 |
公元前 | 2000-09-13 | 0 | 0 |
公元前 | 2000-09-14 | 0 | 0 |
公元前 | 2000-09-15 | 1 | 1 |
CD | 2000-05-23 | 1 | 1 |
CD | 2000-05-24 | 0 | 0 |
CD | 2000-05-25 | 1 | 1 |
CD | 2000-05-26 | 1 | 2 |
任何帮助都会很棒。谢谢!
(下面的所有方法都假设
first(issue)
或 issue[1]
本身就足够“真实”,如 n 0
或 FALSE
。如果您的真实数据没有那么幸运,则需要更新条件(例如,issue[1] > 0
也可以在这里使用)。
我们将使用
consecutive_id()
(用于行程编码),然后分组来计算天数。
library(dplyr)
df |>
mutate(ticket = consecutive_id(customer, issue)) |>
mutate(duration = if (first(issue)) as.numeric(date - min(date)) + 1 else 0, .by = c(customer, ticket))
# customer date issue ticket duration
# 1 AB 2000-09-11 0 1 0
# 2 AB 2000-09-12 1 2 1
# 3 AB 2000-09-13 1 2 2
# 4 AB 2000-09-14 1 2 3
# 5 AB 2000-09-15 1 2 4
# 6 BC 2000-09-13 0 3 0
# 7 BC 2000-09-14 0 3 0
# 8 BC 2000-09-15 1 4 1
# 9 CD 2001-05-23 1 5 1
# 10 CD 2001-05-24 0 6 0
# 11 CD 2001-05-25 1 7 1
# 12 CD 2001-05-26 1 7 2
更详细一点,逻辑相同。
df$ticket <- with(df, ave(issue, list(customer), FUN = function(z) {
r <- rle(z)
r$values <- seq_along(r$values) * r$values
inverse.rle(r)
}))
df$duration <- with(df, ave(1:nrow(df), list(customer, ticket), FUN = function(i) {
if (length(i) && issue[i][1]) {
as.numeric(date[i] - min(date[i])) + 1
} else rep(0, length(i))
}))
df
# customer date issue ticket duration
# 1 AB 2000-09-11 0 0 0
# 2 AB 2000-09-12 1 2 1
# 3 AB 2000-09-13 1 2 2
# 4 AB 2000-09-14 1 2 3
# 5 AB 2000-09-15 1 2 4
# 6 BC 2000-09-13 0 0 0
# 7 BC 2000-09-14 0 0 0
# 8 BC 2000-09-15 1 2 1
# 9 CD 2001-05-23 1 1 1
# 10 CD 2001-05-24 0 0 0
# 11 CD 2001-05-25 1 3 1
# 12 CD 2001-05-26 1 3 2
与
dplyr
步骤非常相似。
library(data.table)
as.data.table(df)[, ticket := rleid(issue),
by = "customer"
][, duration := if (first(issue)) as.numeric(date - min(date)) + 1 else 0,
by = c("customer", "ticket")]
A
data.table
oneliner 可以
library(data.table)
setDT(df)[, duration := ifelse(issue == 0, 0, date - date[1] + 1), by = .(customer, rleid(issue))]
输出
customer date issue duration
1: AB 2000-09-11 0 0
2: AB 2000-09-12 1 1
3: AB 2000-09-13 1 2
4: AB 2000-09-14 1 3
5: AB 2000-09-15 1 4
6: BC 2000-09-13 0 0
7: BC 2000-09-14 0 0
8: BC 2000-09-15 1 1
9: CD 2001-05-23 1 1
10: CD 2001-05-24 0 0
11: CD 2001-05-25 1 1
12: CD 2001-05-26 1 2