【问题标题】:How to create new variable based on time and preexisting variables?如何根据时间和预先存在的变量创建新变量?
【发布时间】:2019-08-13 21:54:47
【问题描述】:

我有一个数据集,随着时间的推移对多个人进行重复测量。它看起来像这样:

   ID           Time    Event      
   1   Jan 1 2012, 4pm    Abx            
   1   Jan 2 2012, 2pm   Test            
   1   Jan 26 2012 3 pm  Test            
   1  Jan 29 2012 10 pm   Abx            
   1  Jan 30 2012, 3 pm  Test            
   1    Jan 5 2012 3 pm  Test            
   2   Jan 1 2012, 4pm    Abx           
   2   Jan 2 2012, 2pm   Test            
   2   Jan 26 2012 3 pm  Test            

数据集当前基于事件。它稍后将被过滤为仅测试。我需要做的是在某个测试时间范围内发生某些事件(在本例中为 Abx)时创建一个新变量,该变量为 1。因此,如果事件“Abx”发生在测试事件的 48 小时内,则新变量应该等于 1。否则,它应该等于 0。 我希望制作这样的东西:

   ID           Time    Event      New_variable
   1   Jan 1 2012, 4pm    Abx            1
   1   Jan 2 2012, 2pm   Test            1
   1   Jan 26 2012 3 pm  Test            0
   1  Jan 29 2012 10 pm   Abx            1
   1  Jan 30 2012, 3 pm  Test            1
   1    Jan 5 2012 3 pm  Test            0
   2   Jan 1 2012, 4pm    Abx            1
   2   Jan 2 2012, 2pm   Test            1
   2   Jan 26 2012 3 pm  Test            0

我知道我可以通过结合使用 Dplyr mutate 函数和 ifelse 语句来解决这个问题,如果我只想在抗生素事件发生时创建一个读取为“1”的变量,我可以这样做:

 test %>%
   mutate(New_variable = ifelse(Event == 'Abx', 1, 0)) -> test2

但我不知道如何考虑时间因素,以便在 Abx 事件的 48 小时内测试事件 = 1。我也不确定如何确保该条件仅适用于同一 ID。我该怎么做?

感谢任何帮助!

更新:非常感谢您的建议! 我将在数据上尝试这些方法,但我认为它们会起作用。如果他们不这样做,我很快就会回来。 成功!我还修改了建议的辅助函数以包含其他选项(用于不止一种类型的 Abx):

 abxRows <- type == "Abx" | type == "Abx2" 

【问题讨论】:

    标签: r if-statement dplyr


    【解决方案1】:

    在提供的数据中,我添加了两个不应为一个的“Abx”事件(即一个不在 48 小时内,另一个与 48 小时内的测试不在同一组)。

    library(dplyr)
    library(lubridate)
    library(purrr)
    
    eventData <-
      data.frame(stringsAsFactors = FALSE,
                 ID = c(1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1),
                 Time = c("Jan 1 2012 4 pm", "Jan 2 2012, 2pm", 
                          "Jan 26 2012 3 pm", "Jan 29 2012 10 pm", 
                          "Jan 30 2012 3 pm", "Jan 5 2012 3 pm",
                          "Jan 1 2012 4 pm", "Jan 2 2012, 2pm",
                          "Jan 26 2012 3 pm", "Feb 12 2012 1pm",
                          "Jan 16 2012 3 pm", "Jan 16 2012 1 pm"),
                 Event = c("Abx", "Test", "Test", "Abx", "Test", "Test", 
                           "Abx", "Test", "Test", "Abx", "Abx", "Test")
      ) %>%
      mutate(Time = mdy_h(Time),
             window = if_else(Event == "Test", 
                              interval(Time - hours(48), Time + hours(48)),
                              interval(NA, NA))
      )
    

    首先,您要确保Time 列是时间格式。然后创建一列 lubridate Interval 类,该类在“测试”事件周围创建一个 48 小时窗口。

    定义将检查事件是否在窗口内发生的辅助函数。

    chkFun <- function(eventTime, intervals, grp, type){
    
      abxRows <- type == "Abx"
      testRows <- !abxRows
    
      hits <- map2_lgl(eventTime, grp, 
                       ~any(.x %within% intervals[grp %in% .y], na.rm = TRUE)) &
        abxRows
    
      testHits <- map_lgl(which(testRows), 
                          ~any(eventTime[abxRows & (grp[.x] == grp)] %within% 
                                 intervals[.x])) 
    
      hits[testRows] <- testHits
    
      as.integer(hits)
    
    }
    

    此函数首先通过并测试“Abx”事件是否在间隔内发生。然后它确定哪些“测试”行具有包含“Abx”事件的间隔。该函数将这些转换的组合作为整数返回。

    最后,只需使用带有辅助函数的 mutate 语句,删除窗口列

    eventData %>%
      mutate(New_variable = chkFun(Time, window, ID, Event)) %>%
      select(-window)
    

    或者,辅助函数可以只将 data.frame 作为参数并假设列名。不过,在上面的表格中,如果你先在脚本中定义它,它也可以在eventData的原始定义中使用

    结果:

    #>    ID                Time Event New_variable
    #> 1   1 2012-01-01 16:00:00   Abx            1
    #> 2   1 2012-01-02 14:00:00  Test            1
    #> 3   1 2012-01-26 15:00:00  Test            0
    #> 4   1 2012-01-29 22:00:00   Abx            1
    #> 5   1 2012-01-30 15:00:00  Test            1
    #> 6   1 2012-01-05 15:00:00  Test            0
    #> 7   2 2012-01-01 16:00:00   Abx            1
    #> 8   2 2012-01-02 14:00:00  Test            1
    #> 9   2 2012-01-26 15:00:00  Test            0
    #> 10  2 2012-02-12 13:00:00   Abx            0
    #> 11  2 2012-01-16 15:00:00   Abx            0
    #> 12  1 2012-01-16 13:00:00  Test            0
    

    【讨论】:

      【解决方案2】:

      所以我没有你的数据副本,所以我不确定你的日期是什么 kmat...

      我建议使用as.POSIXct(Time, format="%b %d %Y, %I%p") 将日期转换为正确的格式。有关格式的更多信息,请查看?strptime,但我认为这适合您的专栏。

      如果我们假设您的数据框是这样的......我知道我已经更改了其中的一部分,但这是为了简单起见

      df <- data.frame(ID = c(rep(1,6),rep(2,3)),
                       Time=c(seq(from=start, by=interval*6840, to=end)[1:6],seq(from=start, by=interval*6840, to=end)[1:3]),
                       Event = rep(c("Abs","Test","Test"),3))
      

      看起来像这样

        ID                Time Event
      1  1 2012-01-01 00:00:00   Abs
      2  1 2012-01-05 18:00:00  Test
      3  1 2012-01-10 12:00:00  Test
      4  1 2012-01-15 06:00:00   Abs
      5  1 2012-01-20 00:00:00  Test
      6  1 2012-01-24 18:00:00  Test
      7  2 2012-01-01 00:00:00   Abs
      8  2 2012-01-05 18:00:00  Test
      9  2 2012-01-10 12:00:00  Test
      

      因此您可以使用以下代码来测试Test 是否在Abs 的48 小时内

      df[which(df$Event=="Test"),]$Time %in% unlist(Map(`:`, df[which(df$Event=="Abs"),]$Time-48*60*60, df[which(df$Event=="Abs"),]$Time+48*60*60))
      

      所以这将返回 FALSE,但这是因为合成数据的时间步长较大。

      要解压这个... df[which(df$Event=="Test"),]$Time 给出测试次数

      %in% 表示在它后面的一组值中查找前面的内容。

      接下来是:unlist(Map(`:`, df[which(df$Event=="Abs"),]$Time-48*60*60, df[which(df$Event=="Abs"),]$Time+48*60*60)) 这会从每个 Abs 创建一个 +/- 48 小时的日期列表。加或减 48 小时,像这样的 POSIXct 对象在几秒钟内完成,因此 48*60*60

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-03-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-24
        • 1970-01-01
        相关资源
        最近更新 更多