【问题标题】:Identify and label repeated data in a series识别和标记系列中的重复数据
【发布时间】:2019-09-02 14:57:42
【问题描述】:

我正在尝试识别数据集中某个值连续多次出现的情况,一旦拾取该值,第 n 次出现一侧的行将用“1”确认这一点。

df<-data.frame(user=c(1,1,1,1,2,3,3,3,4,4,4,4,4,4,4,4),
               week=c(1,2,3,4,1,1,2,3,1,2,3,4,5,6,7,8),
               updated=c(1,0,1,1,1,1,1,1,1,1,0,0,0,0,1,1))

在这种情况下,用户正在执行一项任务。如果执行了任务,则该周显示“1”,否则显示“0”。

如果在一行中遇到四个或更多 0,是否有可能将一个指示符突变为一个新列,以标识该序列已发生?像这样的:

   user week updated warning
1     1    1       1       0
2     1    2       0       0
3     1    3       1       0
4     1    4       1       0
5     2    1       1       0
6     3    1       1       0
7     3    2       1       0
8     3    3       1       0
9     4    1       1       0
10    4    2       1       0
11    4    3       0       0
12    4    4       0       0
13    4    5       0       0
14    4    6       0       1
15    4    7       1       0
16    4    8       1       0

谢谢!

编辑:

道歉并感谢 @akrun 对此提供的帮助。

下面的其他示例,在第 4 次出现等于“1”的错过条目时,警告列将更新以显示事件,触发器将在该事件中运行该数据。

df<-data.frame(user=c(1,1,1,1,2,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7),
               week=c(1,2,3,4,1,1,2,3,1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,1,2,3,4,5,6,7,8),
               missed=c(0,1,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,0,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,1,1,0,1))

   user week missed warning
1     1    1      0       0
2     1    2      1       0
3     1    3      0       0
4     1    4      0       0
5     2    1      0       0
6     3    1      0       0
7     3    2      0       0
8     3    3      0       0
9     4    1      0       0
10    4    2      0       0
11    4    3      1       0
12    4    4      1       0
13    4    5      1       0
14    4    6      1       1
15    4    7      0       0
16    4    8      0       0
17    5    1      0       0
18    5    2      1       0
19    5    3      0       0
20    5    4      1       0
21    5    5      0       0
22    5    6      0       0
23    5    7      0       0
24    5    8      0       0
25    6    1      0       0
26    6    2      1       0
27    6    3      1       0
28    6    4      1       0
29    6    5      1       1
30    6    6      1       0
31    6    7      0       0
32    7    1      0       0
33    7    2      0       0
34    7    3      0       0
35    7    4      0       0
36    7    5      1       0
37    7    6      1       0
38    7    7      0       0
39    7    8      1       0

【问题讨论】:

  • @akrun 道歉 - 是的,这将是预期的结果。

标签: r


【解决方案1】:

一个选项是使用rle 来创建警告。按“用户”分组,通过检查“更新”的run-length-idrle)创建“警告”,它将给出相邻的相似“值”和“长度”作为list,创建逻辑条件其中values 为 0,lengths 大于或等于 4。

library(dplyr)
library(data.table)
df %>% 
   group_by(user) %>%   
   mutate(warning = with(rle(updated), rep(!values & lengths >= 4, lengths))) %>%
   group_by(grp = rleid(warning), add = TRUE) %>%
   mutate(warning = if(all(warning)) rep(c(0, 1), c(n()-1, 1)) else 0) %>% 
   ungroup %>%
   select(-grp)
# A tibble: 16 x 4
#    user  week updated warning
#   <dbl> <dbl>   <dbl>   <dbl>
# 1     1     1       1       0
# 2     1     2       0       0
# 3     1     3       1       0
# 4     1     4       1       0
# 5     2     1       1       0
# 6     3     1       1       0
# 7     3     2       1       0
# 8     3     3       1       0
# 9     4     1       1       0
#10     4     2       1       0
#11     4     3       0       0
#12     4     4       0       0
#13     4     5       0       0
#14     4     6       0       1
#15     4     7       1       0
#16     4     8       1       0

如果我们需要标记 any 有超过 4 个 0 的组,那么

df %>%   
    group_by(user) %>%   
    mutate(warning = with(rle(updated), rep(!values & lengths >= 4, lengths)),
           warning = as.integer(any(warning)))
# A tibble: 16 x 4
# Groups:   user [4]
#    user  week updated warning
#   <dbl> <dbl>   <dbl>   <int>
# 1     1     1       1       0
# 2     1     2       0       0
# 3     1     3       1       0
# 4     1     4       1       0
# 5     2     1       1       0
# 6     3     1       1       0
# 7     3     2       1       0
# 8     3     3       1       0
# 9     4     1       1       1
#10     4     2       1       1
#11     4     3       0       1
#12     4     4       0       1
#13     4     5       0       1
#14     4     6       0       1
#15     4     7       1       1
#16     4     8       1       1

【讨论】:

  • 这太棒了,谢谢!真的有可能在第四次出现之后出现 TRUE 吗?编辑:抱歉,刚刚看到更新!
  • 抱歉 - 评论基于您提交的第一个版本 - 从外观上看,您已经涵盖了这一点!当我运行上述程序时,我遇到了:rleid 中的错误(警告):找不到函数“rleid”
  • 谢谢!这确实帮助并揭示了更多我不知道的功能。出于好奇,如果我们要查找的值与 0 不同,那么仅使用前三行(不包括库)将“!values”更改为我们要查找的值就足以执行匹配?所以说不是 0,而是 1 是我们正在寻找的重复匹配项。
  • @Nodeswitch 你可以使用val &lt;- 2; values == val 这里!values 有点像values == 0
  • 感谢所有帮助!有没有一种简单的方法可以在连续四个阶段标记警告?我试过玩一下,但认为我可能需要添加一个 for 循环?
【解决方案2】:

我采用了不同的方法。我对每个用户updated 为0 和releid(updated) 的情况按顺序编号。如果有4,表示连续有4个作业没有完成。因此,warning 在新向量等于 4 的位置创建。

library(data.table)

   df[, 
      warning := {id <- 1:.N; 
                  warning <- as.numeric(id == 4)}, 
      by = .(user, 
             rleid(updated))][, 
                              warning := ifelse(warning == 1 & updated == 0, 1, 0)][is.na(warning),
   warning := 0]

那里做了什么

  • warning :={}warning 之间的序列的结果赋值。

现在,在序列内部:

  • id &lt;- 1:.N 创建一个临时变量id 变量,其中包含每个用户的连续数字和updated 值的运行长度组。
  • warning &lt;- as.numeric(id == 4) 创建一个临时变量,如果 id2 等于 4,则为 1,否则为零。

by = .(user, rleid(updated)) 按更新后的用户和运行长度值分组。当然updated == 1 有游程值,所以我们通过ifelse 子句去掉它们。最后的[is.na(warning), warning := 0](注意链接)只是去掉了结果变量中的NA值。

使用的数据

> dput(df2)
structure(list(user = c(1, 1, 1, 1, 2, 3, 3, 3, 4, 4, 4, 4, 4, 
4, 4, 4, 5, 5, 5, 5, 5), week = c(1, 2, 3, 4, 1, 1, 2, 3, 1, 
2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5), updated = c(1, 0, 1, 1, 
1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0)), row.names = c(NA, 
-21L), class = c("data.table", "data.frame"))

速度比较

我只是比较了@akrun 的回答:

set.seed(1)
df <- data.table(user = sample(1:10, 100, TRUE), updated = sample(c(1, 0), 100, TRUE), key = "user")
df[, week := 1:.N, by = user]

akrun <- function(df4){
   df4 %>%
   group_by(user) %>%
   mutate(warning = with(rle(updated), rep(!values & lengths >= 4, lengths))) %>%
   group_by(grp = rleid(warning), add = TRUE) %>%
   mutate(warning = if(all(warning)) rep(c(0, 1), c(n()-1, 1)) else 0) %>%
   ungroup %>%
   select(-grp)
}

pavo <- function(df4){
   df4[, warning := {id <- 1:.N; warning <- as.numeric(id == 4)}, by = .(user, rleid(updated))][, warning := ifelse(warning == 1 & updated == 0, 1, 0)][is.na(warning), warning := 0]
}

microbenchmark(akrun(df), pavo(df), times = 100)
Unit: microseconds
      expr      min       lq      mean    median        uq      max neval
 akrun(df) 1920.278 2144.049 2405.0332 2245.1735 2308.0145 6901.939   100
  pavo(df)  823.193  877.061  978.7166  928.0695  991.5365 4905.450   100

【讨论】:

  • 感谢另一个解决方案!我一直在处理这个以及上面的问题,我只是想从中获得另一个功能,它是在第 4 次出现时标记警告,而不是在错过了 9 周的情况下说第 9 次。这输入的动作在第 4 个事件的基础上起作用,虽然其他事件仍然有用,但第 4 个是主要兴趣。我对 R 真的很陌生,对它不太了解。在这里向函数添加计数会起作用吗?
  • 我认为我提供的函数将准确标记连续 0 的第 4 次出现(我可能错了,但我认为 Akrun 标记了连续 0 的 las,如果它们超过 4 个)。我不太明白您为什么需要计数器...尝试研究我为速度比较提供的模拟数据,用户 3 和 10 已发出警告,您可以看到两种解决方案之间的差异。如果您需要额外的东西,请告诉我
  • 你是对的,它的工作方式与所述完全一致。谢谢!
猜你喜欢
  • 2022-01-17
  • 2022-01-16
  • 2015-09-26
  • 1970-01-01
  • 1970-01-01
  • 2020-04-22
  • 2020-04-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多