R 如何找到数据中的差距并在差距太大时进行分类

R How find gaps in data and classify if gaps are to large

我有以下类型的数据:

all_exercises <- c(1,2,9,4,5,7,6,8,3)

user_id <- c(14,14,14,14,14,16,16,16,16,16)
exercise_id <- c(1,2,9,4,5,1,2,4,5,6)
df <- data.frame(user_id,exercise_id)

df

       user_id exercise_id
1       14           1
2       14           2
3       14           9
4       14           4
5       14           5
6       16           1
7       16           2
8       16           4
9       16           5
10      16           6

现在我有兴趣找到没有连续完成所有练习 3 次的用户。练习的顺序与 1:9 有点不同,如果用户之间有差距,他也会被考虑。在我的示例中,用户 14 退出,因为他没有参加练习 7、6、8、3。用户 16 没有被淘汰,因为练习的差距最大为 2。

这是 dplyr 的解决方案,但这可能是重复的...

library(dplyr)

df.gaps <- df %>%
  arrange(user_id, exercise_id) %>%
  group_by(user_id) %>%
  mutate(gap = exercise_id - lag(exercise_id, default = 0))

df.gaps %>%
  filter(gap > 3)

df.gapsuser_idexercise_id 对数据进行排序(假设练习按顺序进行)。然后,我们 group_by user_id 以创建 window 函数差异(请参阅 this window functions vignette)——我还设置了默认值零,不会导致 [=18] =].

最后,您可以过滤这个新的 df.gaps data.frame 以获得结果。


基础 R 解决方案可能如下所示:

df <- df[order(df$user_id, df$exercise_id), ]
temp <- by(df$exercise_id, df$user_id, function(x) diff(x) > 3)
sapply(temp, any)

解决方案

df.gaps <- df %>%
  mutate(exercise_id = factor(exercise_id, all_exercises)) %>%
  arrange(user_id, exercise_id) %>%
  mutate(exercise_id_num = as.numeric(exercise_id)) %>%
  group_by(user_id) %>%
  mutate(gap = lead(exercise_id_num) - exercise_id_num - 1)
  mutate(gap = ifelse(is.na(gap), nlevels(all_exercises)-exercise_id_num, no=gap))


df.gaps
   user_id exercise_id exercise_id_num   gap
     <dbl>      <fctr>           <dbl> <dbl>
1       14           1               1     0
2       14           2               2     0
3       14           9               3     0
4       14           4               4     0
5       14           5               5     4
6       16           1               1     0
7       16           2               2     1
8       16           4               4     0
9       16           5               5     1
10      16           6               7     2