【问题标题】:cohort analysis in RR中的队列分析
【发布时间】:2017-06-06 18:18:27
【问题描述】:

我有一个用户 ID 的数据集 test 以及用户 ID 进行交易的季度:

> test
   id quarter
1   7      Q1
2   7      Q1
3   5      Q1
4   8      Q1
5   3      Q1
6   6      Q1
7  10      Q1
8   3      Q2
9  10      Q2
10  8      Q2
11  2      Q2
12  7      Q2
13  6      Q2
14  6      Q3
15  9      Q3
16  6      Q3
17  4      Q3
18  9      Q3
19  2      Q3
20  5      Q4
21  8      Q4
22 10      Q4
23  7      Q4
24  1      Q4
25  8      Q4

我的目标是找出在第 1 季度活跃的唯一用户数量,并在这些用户中获得在随后几个季度进行交易的用户数量。

上述示例的输出应该是:

> output
  quarter unique_cohort_ids
1      Q1                 6
2      Q2                 5
3      Q3                 1
4      Q4                 4

以下代码有效,但冗长且重复,不适合包含数十个季度的大型数据集。任何有关如何改进它的建议将不胜感激:

subsets <-split(test, test$quarter, drop=TRUE)

for (i in 1:length(subsets)) {
  assign(paste0("Q", i), as.data.frame(subsets[[i]]))
}

Q1_ids <- sum(uniqueQ1$id)
Q2_ids <- sum(unique(Q1$id) %in% unique(Q2$id))
Q3_ids <- sum(unique(Q1$id) %in% unique(Q3$id))
Q4_ids <- sum(unique(Q1$id) %in% unique(Q4$id)) 

群组分析还包括计算新用户的数量 每季度。与手动计算每个季度出现的、以前任何季度都没有出现的唯一用户 ID 不同,我正在寻求一种程序化的解决方案。在这种情况下,输出将是以下列表:

> mylist
[[1]]
[1]  7  5  8  3  6 10

[[2]]
[1] 2

[[3]]
[1] 9 4

[[4]]
[1] 1

任何建议将不胜感激

这里是示例数据:

> dput(test)
structure(list(id = c(7, 7, 5, 8, 3, 6, 10, 3, 10, 8, 2, 7, 6, 
6, 9, 6, 4, 9, 2, 5, 8, 10, 7, 1, 8), quarter = c("Q1", "Q1", 
"Q1", "Q1", "Q1", "Q1", "Q1", "Q2", "Q2", "Q2", "Q2", "Q2", "Q2", 
"Q3", "Q3", "Q3", "Q3", "Q3", "Q3", "Q4", "Q4", "Q4", "Q4", "Q4", 
"Q4")), .Names = c("id", "quarter"), row.names = c(NA, -25L), class = "data.frame")

【问题讨论】:

  • lapply 也许?

标签: r dplyr aggregate


【解决方案1】:

这是一个使用 data.table 的示例

library(data.table)
setDT(test)[, sum(unique(id) %in% test[quarter=="Q1", id]), by = quarter]

#   quarter V1
#1:      Q1  6
#2:      Q2  5
#3:      Q3  1
#4:      Q4  4

对于第二部分的分析:

split(test$id[!duplicated(test$id)], test$quarter[!duplicated(test$id)])

#$Q1
#[1]  7  5  8  3  6 10

#$Q2
#[1] 2

#$Q3
#[1] 9 4

#$Q4
#[1] 1

根据新要求更新:

这对我来说似乎有点笨拙,但这是跟踪你在每个季度中看到的 ID 的最简单方法。

quarts <- sort(unique(test$quarter))
test$occur <- 1
mat <- dcast.data.table(test, id ~ quarter, value.var = "occur", fun.aggregate = sum)

res <- mat[Q1 >0, lapply(.SD, function(x) sum(x>0)), .SDcols=colnames(mat)[-1]] ##initalize the results with "Q1"
cumMat <- mat$Q1 ##this will keep track of the ids that were seen in previous quarters  

for(i in quarts[-1]){                                  ##foreach quarter (except ("Q1") we will count the number of unique ids that are in that quarter and not in any previous quarters.
  res <- rbind(res, mat[cumMat == 0 & get(i) > 0, lapply(.SD, function(x) sum(x>0)), .SDcols=colnames(mat)[-1]])
  cumMat <- rowSums(cbind(cumMat, mat[, i, with = F])) ##update the ids seen
}
t(res) 

#   [,1] [,2] [,3] [,4]
#Q1    6    0    0    0
#Q2    5    1    0    0
#Q3    1    1    2    0
#Q4    4    0    0    1

【讨论】:

  • 谢谢,这行得通,但是解决方案的第一部分的问题是它不能应用于 Q2、Q3 和 Q4。例如,setDT(test)[, sum(unique(id) %in% test[quarter=="Q2", id]), by = quarter] 产生的输出 V1 为 5, 6, 2, 3,但该输出实际上应该是 0, 1, 1, 0,因为在 Q2 中只有一个新 id,并且该 id 出现在 Q3 而不是 Q4
  • 这有意义吗?
  • 是的,但请注意这不是您最初要求的。
【解决方案2】:

这种方法怎么样?

library(tidyverse)
test %>% 
distinct() %>% 
mutate(value = T) %>% 
spread(quarter, value) %>% 
filter(!is.na(Q1)) %>%
select(-id) %>%
colSums(na.rm = T)
# Q1 Q2 Q3 Q4 
# 6  5  1  4 

【讨论】:

    【解决方案3】:

    对于每季度的独特同类群组计数:

    q1_ids <- test[test$quarter == 'Q1', 'id']
    test_from_q1 <- test[test$id %in% q1_ids, ]
    unique_from_q1 <- unique(test_from_q1)
    quarter_counts <- table(unique_from_q1$quarter)
    output <- as.data.frame(quarter_counts)
    names(output) <- c('quarter', 'unique_cohort_ids')
    

    对于第二部分,data.frame 是否可以接受?

    unique_ids <- unique(test$id)
    first_appearance <- data.frame(
      id = unique_ids,
      quarter = test$quarter[match(unique_ids, test$id)]
    )
    

    如果没有,那么 tapply 可以列出它:

    tapply(
        first_appearance$id,
        first_appearance$quarter,
        'identity',
        simplify = FALSE
    )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-01
      • 2018-10-21
      • 2014-11-09
      相关资源
      最近更新 更多