【问题标题】:Event Counter with condition有条件的事件计数器
【发布时间】:2017-07-18 07:34:46
【问题描述】:

下面是一个数据框df,它有1个变量ID,有500K个数据点,我需要在以下条件下实现event counter
1。当 ID == A
2 时增加 event counter。尽管ID == A,但不应考虑前 3 个数据点作为计数器增量。
下面显示了具有预期输出的数据框df

ID       Event Counter  
D          0  
F          0  
V          0
A          0  
A          0  
A          0
A          1  
A          1  
A          1
V          1  
F          1  
A          1
A          1
A          1  
A          2  
F          2  
G          2 
A          2  
A          2  
A          2  
A          3  
A          3  

请注意:- 行号 1,2 和 3 不满足条件,因此 Event Counter 中没有增量。尽管ID ==A 在第 4,5 和 6 行,event counter 不会增加(参考:条件 2)。在行号 12,13 和 14 的情况下相同。

发现类似的问题,每次遇到满足条件的数据点时计数器都会增加,但我的实现条件不同。

【问题讨论】:

  • 另一种情况:如果A有连续8个(或多于6个)值怎么办?它还会继续相同的计数器吗?
  • @RonakShah 如果值A 超过 6 ,如果连续出现,则计数器保持相同的值。仅当与事件 ID == A 发生偏差并返回到事件 ID == A 时,计数器才会增加。

标签: r


【解决方案1】:

您可以将zoo::rollsum 结合rle 用于此类任务:

library(zoo)
x <- rollsumr(df$ID == "A", k=4, fill = NA)
df$new <- with(rle(!is.na(x) & x == 4), rep(cumsum(values), lengths))

在这种情况下,k = 4x == 4 意味着您需要 3 个 ID == "A" 的情况才能增加。您可以随意更改此号码。

结果等于你想要的输出:

all.equal(df$Event_counter, df$new)
#[1] TRUE

rle 部分返回:

rle(!is.na(x) & x == 4)
#Run Length Encoding
#  lengths: int [1:6] 6 3 5 1 5 2
#  values : logi [1:6] FALSE TRUE FALSE TRUE FALSE TRUE

现在我们可以 a) 计算值的累积和,即 0-1-1-2 ... b) 使用 rep 我们重复每个值的次数与每个序列的长度相同,即lengths

【讨论】:

  • 这太可爱了!我试图通过rle 得到它
  • 这是一个很好的解决方案。你能向我解释一下 with 语句的长度部分是如何工作的吗?您将 rep(cumsum(values) 应用于 rle(!is.na(x) & x == 4) 的值,留下 0 1 1 2 2 3。此函数如何根据中的值重复这些数字长度?
  • @FlorianMaas,我添加了一些解释。
  • 啊,我明白了,我最初忽略了代表声明...非常感谢!
【解决方案2】:

这似乎是你想要的:

df = read.table(text="ID Event_counter 
D          0  
F          0  
V          0
A          0  
A          0  
A          0
A          1  
A          1  
A          1
V          1  
F          1  
A          1
A          1
A          1  
A          2  
F          2  
G          2 
A          2  
A          2  
A          2  
A          3  
A          3",header=TRUE)

indices = df$ID=="A"
reset.counter = indices!=c(NA,head(indices,-1))& indices==FALSE & c(NA,head(indices,-1))==TRUE
indices <- unname(split(indices, cumsum(seq_along(indices) %in% which(reset.counter))))
indices=unlist(lapply(indices, function(x) cumsum(x)==4 & x==TRUE))
df$Event_counter_check =  cumsum(indices)

输出

   ID Event_counter Event_counter_check
1   D             0                   0
2   F             0                   0
3   V             0                   0
4   A             0                   0
5   A             0                   0
6   A             0                   0
7   A             1                   1
8   A             1                   1
9   A             1                   1
10  V             1                   1
11  F             1                   1
12  A             1                   1
13  A             1                   1
14  A             1                   1
15  A             2                   2
16  F             2                   2
17  G             2                   2
18  A             2                   2
19  A             2                   2
20  A             2                   2
21  A             3                   3
22  A             3                   3

希望这会有所帮助!

【讨论】:

  • @FlorianMass 您的代码也运行良好,非常感谢。
  • 谢谢,你真好。下一次我研究了 Docendo 的代码 ;)
【解决方案3】:

这是使用 splitlapply 的基本 R 替代方案。

dat$v3 <-
  cumsum(unlist(lapply(split(dat$ID,
                           with(rle(as.character(dat$ID)), rep(seq_along(values), lengths))),
                       function(x) {
                         v <- length(x)
                         if(x[1] == "A" && v > 3) rep(c(0, 1, 0), c(3, 1, v-4))
                         else rep(0, v)
                       })))

使用与 docendo-discimus 的答案类似的方法拆分 ID 变量,拆分相同 ID 的运行。这个列表被提供给lapply,它检查组是否由 As 组成,以及组是否至少有 3 个元素。如果是这样,则返回一个具有 3 个 0 后跟一个 1 且其余元素为 0 的向量以匹配向量的长度。如果检查失败,则返回适当长度的 0 向量。

返回

dat
   ID Event_Counter v3
1   D             0  0
2   F             0  0
3   V             0  0
4   A             0  0
5   A             0  0
6   A             0  0
7   A             1  1
8   A             1  1
9   A             1  1
10  V             1  1
11  F             1  1
12  A             1  1
13  A             1  1
14  A             1  1
15  A             2  2
16  F             2  2
17  G             2  2
18  A             2  2
19  A             2  2
20  A             2  2
21  A             3  3
22  A             3  3

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-02-28
    • 1970-01-01
    • 1970-01-01
    • 2017-12-25
    • 2020-10-25
    • 2014-01-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多