【问题标题】:Finding Time Difference Between Observations in R在 R 中查找观测值之间的时差
【发布时间】:2014-11-03 22:27:45
【问题描述】:

我正在尝试确定两次观察之间的时间差。数据由不同的个人分解,每个人都有自己的唯一 ID。我有一个数据集,它告诉我每次更改时他们的状态更新,以及他们的状态何时更改。状态可以是两个值之一,并且它总是会更改为不是的值(在这种情况下,从 Y 到 N,或从 N 到 Y)。

数据如下:

ID Status Time
1    Y     2013-07-01 08:07:00      
2    Y     2013-07-01 08:07:03  
3    Y     2013-07-01 08:07:04      
4    Y     2013-07-01 08:07:06      
1    N     2013-07-01 08:07:07      
2    N     2013-07-01 08:07:23      
5    Y     2013-07-01 08:07:34  
6    Y     2013-07-01 08:07:45  
7    Y     2013-07-01 08:07:47  
1    Y     2013-07-01 08:07:56  
3    N     2013-07-01 08:07:58  

我想找到的是每个 ID 的每次状态更改之间经过的时间量 - 即从 Y 到 N 需要多长时间。然后获得汇总统计信息,例如经过的分布时间,经过时间的平均值等。

因此示例输出可能如下所示,记录上面发生的三个 Y 到 N 切换(1 个切换、2 个切换和 3 个切换)

Y to N change    Time elapsed (in seconds)
1                     7 
2                     20
3                     54

由于某种原因,我遇到了很多麻烦。现在我有 POSIXlt 格式的时间,以及 ID 和状态作为一个因素。我曾尝试使用 ddply 按 ID 然后按时间戳对数据进行排序,但到目前为止还没有奏效。任何建议将不胜感激!

编辑:将时间更改为正确的类型。

Edit2:在等待更多答案时最终编写了一个解决方案。我的方式比这里的许多解决方案都要丑陋得多,但我做到了:

N <- ifelse(df$Status=="N",1,0)
Y <- ifelse(df$Status== "Y",1,0)

#making a vector which is 1 for a row if the item status of the row below it is N
var1 <- N
for (i in 1:nrow(df)) {
  var1[i] <- N[i+1]
}

#making a vector which is TRUE if a row's item status is Y and the row after is N
check <- ifelse(var1==s & var1==1,TRUE,FALSE)
#had to define the last one as FALSE manually because the for loop above would miss the last entry due to how it was constructed
check [50000]=FALSE



#made a loop which finds the time difference for a row's TIME and the row below it, given that "check " is true for that row, and writes that to a results vector.
#here is the results vector
results <- numeric(nrow(df))
#here is the for loop
for (i in 1:nrow(df)) {
  if(check [i]){
    results[i] <- difftime(df$Time[i],df$Time[i+1])
  }
}

我最初使用 for 循环解决了这个问题,但是在我实际数据集的大约 100 万行中,它太慢了,所以我做了这个矢量化的东西。这些其他解决方案是否适用于这么大的数据?我一定会尝试一下!

【问题讨论】:

    标签: r datetime


    【解决方案1】:

    这是另一种方法。我试图将所有数据留在最终输出中。请注意,出于演示目的,我稍微修改了您的数据。在我的代码中,我首先按ID 和Time 排列数据。然后,我将 Status(即 Y 和 N)更改为 0 和 1,以创建 group。在这里,group 可以告诉我们Status 何时更改。如果您看到几行出现相同的数字,则表示Status 没有改变。然后,我计算了每个 ID 的时间差(即gap)。最后,我将每个组第一行中没有出现的gap 值更改为NA。也就是说,我做了不必要的间隙NA。请注意,每个 ID 的第一个观察值在 gap 中也有 NA。 gap 排在第二位。

    ann <- data.frame(ID = c(1,2,3,4,1,2,2,1,1,1,3),
                      Status = c("Y", "Y", "Y", "Y",
                                 "N", "N", "Y", "Y", "Y", "N", "N"),
                      Time = c("2013-07-01 08:07:00", "2013-07-01 08:07:03",
                               "2013-07-01 08:07:04", "2013-07-01 08:07:06",
                               "2013-07-01 08:07:07", "2013-07-01 08:07:23",
                               "2013-07-01 08:07:34", "2013-07-01 08:07:45",
                               "2013-07-01 08:07:47", "2013-07-01 08:07:56",
                               "2013-07-01 08:07:58"),
                      stringsAsFactors = FALSE)
    
    ann$Time <- as.POSIXct(ann$Time)
    
    #   ID Status                Time
    #1   1      Y 2013-07-01 08:07:00
    #2   2      Y 2013-07-01 08:07:03
    #3   3      Y 2013-07-01 08:07:04
    #4   4      Y 2013-07-01 08:07:06
    #5   1      N 2013-07-01 08:07:07
    #6   2      N 2013-07-01 08:07:23
    #7   2      Y 2013-07-01 08:07:34
    #8   1      Y 2013-07-01 08:07:45
    #9   1      Y 2013-07-01 08:07:47
    #10  1      N 2013-07-01 08:07:56
    #11  3      N 2013-07-01 08:07:58
    
    ann %>%
        arrange(ID, Time) %>%
        group_by(ID) %>%
        mutate(Status = ifelse(Status == "Y", 1, 0),
               group = cumsum(c(T, diff(Status) != 0)),
               gap = Time - lag(Time)) %>%
        group_by(ID, group) %>%
        mutate(gap = ifelse(row_number() != 1, NA, gap))
    
    #   ID Status                Time group gap
    #1   1      1 2013-07-01 08:07:00     1  NA
    #2   1      0 2013-07-01 08:07:07     2   7
    #3   1      1 2013-07-01 08:07:45     3  38
    #4   1      1 2013-07-01 08:07:47     3  NA
    #5   1      0 2013-07-01 08:07:56     4   9
    #6   2      1 2013-07-01 08:07:03     1  NA
    #7   2      0 2013-07-01 08:07:23     2  20
    #8   2      1 2013-07-01 08:07:34     3  11
    #9   3      1 2013-07-01 08:07:04     1  NA
    #10  3      0 2013-07-01 08:07:58     2  54
    #11  4      1 2013-07-01 08:07:06     1  NA
    

    【讨论】:

    • 实际上是一个问题——我得到一个错误:“错误:列'gap'的类型不受支持”尝试运行它时。有任何想法吗?不过非常酷的解决方案!
    • @verybadatthis 你有哪个版本的dplyr?我正在使用dplyr_0.3.0.9000。这是来自 Github 的开发版本。
    • @verybadatthis 我的 R 版本是 3.1.1。
    【解决方案2】:

    这似乎适用于您提供的示例数据,但那些时间不是 POSIXlt。这将找到第一个Y 时间和第一个N 时间,删除没有从Y 转换到N 的任何ID,并从第一个N 时间中减去第一个Y 时间.

    library('dplyr')
    
    df <- read.table(text = "ID Status Time
    1    Y     1
    2    Y     2
    3    Y     3.5
    4    Y     4
    1    N     5.8
    2    N     6
    5    Y     7
    6    Y     8
    7    Y     8.1
    1    Y     11
    3    N     12", header = TRUE)
    df$ID <- as.factor(df$ID) # convert ID to factor
    
    df %>%
      group_by(ID, Status) %>%
      summarize(Time = min(Time)) %>%
      filter("N" %in% Status & "Y" %in% Status) %>%
      summarize(Time_elapsed = Time[Status == "N"] - Time[Status == "Y"])
    

    结果:

      ID Time_elapsed
    1  1          4.8
    2  2          4.0
    3  3          8.5
    

    【讨论】:

    • 对不起,我很笨,没有把它们变成 POSIXlt 格式。让我编辑原始问题,我可以看到这是如何引起混乱的。如所写,代码不适用于 POSIXlt 类型时间,但我将看看是否可以将时间转换为整数,然后使用您的解决方案。一个快速的问题:这段代码是否能够处理具有许多状态更改的单个 ID?例如,Y -> N -> Y -> N -> Y?乍一看,它似乎只需要每个 ID 的第一次出现。再次感谢您的帮助!
    • 您可以使用dput() 粘贴带有 POSIXlt 值的实际数据块。此代码不适用于单个 ID 的多个状态更改。没有意识到这是必要的。如果您发布更新的数据,我会尝试相应地编辑我的答案。
    • @verybadatthis 我不明白你希望你的输出是什么样子。在您的评论中,您说您希望查看每个 ID 的所有状态更改,但您在问题中提供的示例输出并未反映这一点。你能澄清一下吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多