【发布时间】:2020-11-23 17:38:26
【问题描述】:
我正在处理用户生成的数据,我想计算行数/活动数,即每个用户在特定时间段内进行的调用。这是一个模拟数据框,类似于我正在使用的:
library(ids)#for generating the UserID variable
library(wakefield)#for generating the Status variable
library(dplyr)
set.seed(123)
UserID<-random_id(n=10, bytes = 5)
DateTime<-seq.POSIXt(from = as.POSIXct("2020-08-01 01:00:00", tz = Sys.timezone()), length.out = 70, by = "15 mins")
df<-cbind(UserID,DateTime)
df<-as.data.frame(df)
df$Status<-r_sample_factor(x = c("Answered", "Abandoned", "Engaged"), n=70)
df$DateTime<-seq.POSIXt(from = as.POSIXct("2020-08-01 01:00:00", tz = Sys.timezone()),
length.out = 70, by = "15 mins")#re-doing this again as it annoyingly converts to numeric each time
df<-df%>%arrange(UserID,DateTime)
head(df)
#UserID DateTime Status
#1 0a5f3a2a8b 2020-08-01 02:00:00 Engaged
#2 0a5f3a2a8b 2020-08-01 04:30:00 Engaged
#3 0a5f3a2a8b 2020-08-01 07:00:00 Engaged
#4 0a5f3a2a8b 2020-08-01 09:30:00 Engaged
#5 0a5f3a2a8b 2020-08-01 12:00:00 Engaged
#6 0a5f3a2a8b 2020-08-01 14:30:00 Abandoned
我想要做的是计算UserID 在 5 小时内的呼叫次数,还有另外两个条件:-
- 如果在用户最后一次呼叫的 5 小时内没有另一个呼叫,那么这将作为一次“尝试”而失败
- 如果用户在 5 小时内有 N 次呼叫直到他们得到“应答”,那么这将被视为一次“成功”尝试。否则,它会被视为“不成功”
这是我想要实现的目标:-
UserId OrigTime LastTime Calls Status Successful
0a5f3a2a8b 2020-08-01 02:00:00 2020-08-01 07:00:00 3 Engaged No
16db61d2bc 2020-08-01 03:15:00 2020-08-01 03:15:00 1 Answered Yes
6355f7700d 2020-08-01 01:00:00 2020-08-01 06:00:00 3 Answered Yes
9b9fab9789 2020-08-01 04:15:00 2020-08-01 09:15:00 3 Answered Yes
...
所以OrigTime 是他们在一次尝试中第一次调用的时间,LastTime 是他们在同一次尝试中最后一次调用的时间。 Calls 列计算用户在该尝试中进行的呼叫次数,Status 是尝试中最后一次呼叫的状态,“成功”可以是合乎逻辑的,表示该尝试中的最后一次呼叫是否被应答.
任何指向正确方向的指针都会很棒。我想有一些data.table 或dplyr 解决方案,但我以前没有做过很多此类活动,所以不知道从哪里开始。非常感谢您提前:)
编辑
@Waldi 提供的解决方案几乎满足了我的需求。这是迄今为止效果最好的解决方案(根据@Waldi 的回答稍作修改):-
CondCount <- function(data,maxdelay){
result <- list()
row <- 0
calls <- 0
OrigTime <- NA
n <- nrow(data)
for (i in 1:n) {
if (is.na(OrigTime)) {
OrigTime <- data$DateTime[[i]]
calls <- 0
}
calls = calls + 1
if (data$Status[[i]] == "Answered" | difftime(data$DateTime[[i]],OrigTime,units='hours') > maxdelay | i==n) {
row <- row + 1
result[[row]] <- data.frame(OrigTime = OrigTime, LastTime = data$DateTime[[i]], calls = calls, Status = factor(data$Status[[i]],levels=c("Answered" ,"Abandoned" ,"Engaged","Unknown")), Successful = ifelse(data$Status[[i]]=="Answered",'Y','N') )
OrigTime <- NA
}
}
dplyr::bind_rows(result)
}
df %>% arrange(UserID,DateTime) %>%
split(.$UserID) %>%
map(function(data) {CondCount(data,1) }) %>%
bind_rows(.id="UserID")
请参阅我在编辑之前编写的 2 个步骤。这一次,时间段是 1 小时,不是 5 小时。
使用@Waldi 的解决方案,它适用于我的真实 df(如果碰巧有任何色盲 SO 用户,我为我使用的颜色编码表示歉意):-
正确的结果
使用@Waldi 的解决方案,它会给你这个:-
这是正确的!这就是我的目标。但是,我想说明两个示例,说明运行此代码时会发生什么,这会产生不希望的结果:-
不正确的结果 1
这给了你这个:-
这是不正确的。它应该是两行,每次尝试一次(每行的最终状态为“已放弃”)而不是一行,因为最后两行之间的时间差大于 60 分钟。
不正确的结果 2
这给了你这个:-
这是不正确的。它应该是两行,每次尝试一个(第一行状态为“已参与”,第二行状态为“已回答”)。
我必须大力赞扬@Waldi,因为该解决方案非常适合接听电话。但是,它没有考虑其他状态类型,即 Abandoned 和 Engaged。这可能是这两种状态没有满足足够条件的情况。一如既往,我们将不胜感激!
【问题讨论】:
-
你能
dput最后两个有错误的例子吗:我想我更正了代码但想测试它。谢谢。
标签: r datetime count data-wrangling multiple-users