【问题标题】:Track first observation based on several criteria in R根据 R 中的几个标准跟踪第一次观察
【发布时间】:2018-01-29 21:36:04
【问题描述】:

我想要一种在 R 中遍历 200 万行的方法,并找到 specified 事件发生时的 第一个 实例,并跟踪它们发生的时间。注意:(1)start event 时间应该出现在end event x 之前,(2) 第 1 行的end event x/end event z 应该出现在第 2 行的start event 之前,等等。

我发现的最接近的另一个例子是:R - Keep first observation per group identified by multiple variables (Stata equivalent "bys var1 var2 : keep if _n == 1")

我的问题是不同,因为我需要 1) 查看多个条件,并且仅包含符合条件的行(thresholdstatus 等),以及 2) 需要以不同的方式格式化它(即拉Timestamp

【问题讨论】:

    标签: r


    【解决方案1】:

    使用 的解决方案。 case_when 可以方便地分配条件。之后,在Flag中删除NA的行,然后在Flag2中分配运行长度ID,在Flag2中过滤第一行,分配Flag2,最后传播数据帧。

    library(dplyr)
    library(tidyr)
    library(data.table)
    
    dat2 <- dat %>%
      mutate(Flag = case_when(
        Enable == 0 & Deviation > Threshold & Status == 0        ~ "Start Event Time",
        Enable == 1 & Deviation > Threshold & Status == 0        ~ "End Event x Time",
        Enable == 1 & Deviation > Threshold & Status == 1        ~ "End Event z Time",
        TRUE                                                     ~ NA_character_
      )) %>%
      drop_na(Flag) %>%
      mutate(Flag2 = rleid(Flag)) %>%
      group_by(Flag2) %>%
      slice(1) %>%
      ungroup() %>%
      mutate(x=cumsum(Flag == "Start Event Time")) %>%
      group_by(x) %>%
      filter(!(duplicated(Flag) & (Flag =='End Event x Time' | Flag =='End Event z Time'))) %>% 
      spread(Flag, Timestamp, x) %>%
      select(ID, `Start Event Time`, `End Event x Time`, `End Event z Time`)
    dat2
    # # A tibble: 3 x 4
    #   ID    `Start Event Time` `End Event x Time` `End Event z Time`
    # * <chr> <chr>              <chr>              <chr>             
    # 1 a     6/10/2015 10:20    6/10/2015 10:25    6/10/2015 10:40   
    # 2 a     6/10/2015 10:55    6/10/2015 11:00    6/10/2015 11:10   
    # 3 b     7/11/2015 11:25    7/12/2015 11:30    7/13/2015 11:35 
    

    【讨论】:

    • 这在我昨天使用的样本数据集上运行良好,但是在我上传的更大的样本数据集上使用时,它会抛出一个Error: Duplicate identifiers for rows (7, 9), (4, 6)
    • @Meg 我很乐意为您提供帮助,但请理解,研究您的问题并找到答案需要时间和精力。当您将示例数据集替换为新数据集时,我感到有点被冒犯了,因为所有这些时间和努力都不值得。昨天提供示例数据集的是您,您是否有责任确保您的示例数据集真正代表您的真实数据?如果代码因为示例数据集和真实单词数据集差异很大而无法工作,为什么不发布一个新问题呢?为什么要更改您原来的问题?
    • 天哪,我根本不想冒犯你! - 我非常感谢您的所有帮助- 我通过您的代码的每一步来更好地理解您的方法,并研究每个功能。我只对 R 有一点了解(这不是借口),但我正在慢慢掌握可重现数据的窍门并理解数据的所有潜在问题(我之前的问题经常被否决)。但你是对的,下次我发布问题时,我会仔细检查数据是否足够具有代表性,如果我让你不高兴了,我很抱歉 - 我真的很感谢你花时间帮助像我这样的新手。
    • 我最终将您的答案与stackoverflow.com/questions/48528734/… 结合起来完成了这个!再次感谢! R很漂亮! :P
    • 谢谢!不用担心,你完全有权叫我出去;)我仍然在这里试图理解你的思维过程:P再次感谢你的帮助:)
    【解决方案2】:

    可能不是最优雅的解决方案,但它似乎可以完成工作。

    library(tidyverse)
    d <- read_csv(
    "ID,  Timestamp,        Enable,      Status,     Deviation,   Threshold
    a,   6/10/2015 10:10,     0,           0,           0.5,     0.65
    a,   6/10/2015 10:15,     0,           0,           0.6,     0.65
    a,   6/10/2015 10:20,     0,           0,           0.75,    0.65
    a,   6/10/2015 10:25,     1,           0,           0.8,     0.65
    a,   6/10/2015 10:30,     1,           0,           0.9,     0.65
    a,   6/10/2015 10:35,     1,           0,           0.8,     0.65
    a,   6/10/2015 10:40,     1,           1,           0.7,     0.65
    a,   6/10/2015 10:45,     1,           1,           0.5,     0.65
    a,   6/10/2015 10:50,     0,           0,           0.6,     0.65
    a,   6/10/2015 10:55,     0,           0,           0.7,     0.65
    a,   6/10/2015 11:00,     1,           0,           0.8,     0.65
    a,   6/10/2015 11:05,     1,           0,           0.9,     0.65
    a,   6/10/2015 11:10,     1,           1,           1,       0.65
    a,   6/10/2015 11:15,     1,           1,           0.8,     0.65
    a,   6/10/2015 11:20,     1,           1,           0.7,     0.65
    b,   7/10/2015 11:20,     0,           0,           0.4,     0.5
    b,   7/11/2015 11:25,     0,           0,           0.6,     0.5
    b,   7/12/2015 11:30,     1,           0,           0.7,     0.5
    b,   7/13/2015 11:35,     1,           1,           0.8,     0.5")
    
    d %>% 
      mutate(
        start = ifelse(Enable == 0 & Deviation > Threshold & Status == 0,
                   1, 
                   0),
        end_x = ifelse(Enable == 1 & Deviation > Threshold, 
                   1, 
                   0),
        end_z = ifelse(Enable == 1 & Deviation > Threshold & Status == 1, 
                   1, 
                   0)) %>%
      gather(var, val, start:end_z) %>% # gather them into a single variable
      filter(val == 1) %>% # remove dummy coding
      select(ID, Timestamp, var) %>% # remove unnecessary variables
      group_by(ID, var) %>% 
      mutate(count = 1:n()) %>% # create count variable so rows are uniquely identified
      spread(var, Timestamp) %>% # spread it back out
      select(ID, start, end_x, end_z) %>% 
      na.omit()
    
      ID    start           end_x           end_z          
      <chr> <chr>           <chr>           <chr>          
    1 a     6/10/2015 10:20 6/10/2015 10:25 6/10/2015 10:40
    2 a     6/10/2015 10:55 6/10/2015 10:30 6/10/2015 11:10
    3 b     7/11/2015 11:25 7/12/2015 11:30 7/13/2015 11:35
    

    【讨论】:

    • 如此接近!我很欣赏快速反应!我能看到的唯一问题是开始事件需要在结束事件之前发生(参见第 2 行)——不过几乎就在那里! :)
    • 那(在结束事件之前开始事件)不是一个逻辑约束吗?事情能在开始之前就结束吗?
    • 好的,但是鉴于您提供的标准和数据,我相信以上是正确的。如果您查看数据的第 5 行,它符合end_x 的标准,即使时间早于符合start 标准的行,除非我误解了?
    • 丹尼尔·安德森——你说得对,我没有具体说明(我只是将其编辑得更清楚)——但是,是的,开始事件需要在之前发生是一种限制结束事件(我认为这可能会让事情变得更棘手)
    • Daniel Anderson - 我还做了另一个说明(我在将您的解决方案应用于我自己的代码时发现了这个错误) - 第 1 行的结束时间应该在第 2 行的开始时间之前发生;再次感谢您的帮助 - 我尝试在 filter(val == 1) 行之后按 Timestamp 使用安排()
    【解决方案3】:

    对于每个“ID”,使用cumsum 根据“开始”的条件创建一个分组变量“g”。对于每个“ID”和“g”,选择相关行。

    library(data.table)
    setDT(d)
    d[ , g := cumsum(Enable == 0 & Deviation > Threshold & Status == 0), by = ID]
    d[g > 0, .(start = Timestamp[1],
               end_x = Timestamp[Enable == 1 & Deviation > Threshold][1],
               end_z = Timestamp[Enable == 1 & Deviation > Threshold & Status == 1][1]),
      by = .(ID, g)]
    #       ID g              start              end_x              end_z
    # 1:     a 1    6/10/2015 10:20    6/10/2015 10:25    6/10/2015 10:40
    # 2:     a 2    6/10/2015 10:55    6/10/2015 11:00    6/10/2015 11:10
    # 3:     b 1    7/11/2015 11:25    7/12/2015 11:30    7/13/2015 11:35
    

    【讨论】:

    • Henrik - 谢谢你的回答。我在 csv 中添加了额外的数据,以更好地映射我的数据中的奇怪之处。看起来您的解决方案跟踪第一个事件,但不匹配(见下文: ID g start end_x end_z 1: a 1 6/10/2015 10:11 NA NA 2: a 2 6/10/2015 10: 12 NA NA 3:a 3 6/10/2015 10:13 NA NA 4:a 4 6/10/2015 10:14 6/10/2015 10:15 6/10/2015 10:45 5:a 5 6 /10/2015 10:55 6/10/2015 11:00 6/10/2015 11:10 6: b 1 7/10/2015 11:22 7/11/2015 11:24 7/11/2015 11: 27)
    • 请花点时间在发布您的问题之前构建足够复杂的示例数据。花时间在一个有效的答案上,解决原来的问题,然后被一个移动的目标问题变成无效的,这是相当令人沮丧的。干杯。
    • 对此深表歉意 - 非常感谢您对此提供的帮助,我绝对有机会通过您的回答进一步探索 data table。这不是借口,但我已经在 R 工作了几个月,并且仍然掌握了可重现数据的窍门,并且在尝试思考我的实际数据集可能存在的问题时特别挣扎。我真的很感谢你和其他人,以及你对 SO 的贡献 - 对于我明显的新手让你感到沮丧,我深表歉意
    猜你喜欢
    • 2021-12-15
    • 1970-01-01
    • 2023-01-18
    • 1970-01-01
    • 2021-11-20
    • 1970-01-01
    • 1970-01-01
    • 2020-05-22
    • 2015-11-30
    相关资源
    最近更新 更多