【问题标题】:Identify consecutive sequences based on a given variable根据给定变量识别连续序列
【发布时间】:2020-04-13 12:04:08
【问题描述】:

我确实坚持这一点。 df1 有以下变量:

  1. serial = 一群人

  2. id1 = 群组中的人(例如,12 (serial) 1 (id1) =group 12 person 1; 12 2 = group 12 person 2, etc。)

  3. 'Day'第一次(或开始)录制时。

这些天由相同数量的观察组成(例如 95 个)

        day1 (Monday)  =  day11-day196 
        day2 (Tuesday) = day21-day296     
        day3 (Wednesday) =  day31-day396   
        day4 (Thursday) =  day41-day496   
        day5 (Friday) = day51-day596      
        day6 (Saturday) = day61-day696   
        day7 (Sunday) =  day71-day796  

df1 示例

serial id1  Day     day1 day2 day3 day4 day5 day6 day7
12      1   Monday    2    1    2    1    1    3    1
123     1   Tuesday   0    3    0    3    3    0    3
10      1   Wednesday 0    3    3    3    3    3    3

我想确定连续记录(每日记录之间没有间隙)和记录总数。

连续录制的开始日期是“Day”变量。例如,连续记录将是序列号 12。记录从星期一开始,并且在一周内有记录(至少有一个来自 95 变量)。一周内(7 x 95 变量)有 11 条记录

不连续的记录将是 id 123,因为在第 3 天和第 6 天有一个间隔日。记录从周二开始,周三和周六有间隔。

最后我想记录下连续录音的时长。

示例输出:

 serial  id1   Duration Occurance        Days
12       1      11        7        day1 day2 day3 day4 day5 day6 day7
123      1      12        0        0
10       1      18        5        day3 day4 day5 day6 day7

样本数据

structure(list(serial = c(12, 123, 10), id1 = c(1, 1, 1), Day = structure(1:3, .Label = c("Monday",
"Tuesday", "Wednesday"), class = "factor"), day1 = c(2, 0, 0),
day2 = c(1, 3, 3), day3 = c(2, 0, 3), day4 = c(1, 3, 3),
day5 = c(1, 3, 3), day6 = c(3, 0, 3), day7 = c(1, 3, 3)), row.names = c(NA,
3L), class = "data.frame")

类似帖子R - identify consecutive sequences

【问题讨论】:

  • 看起来和我昨天回答的另一个问题很相似
  • 如果在第 796 天之前还有列,我只是想知道,您会认为有多少个值是连续的
  • 考虑一行是2 1 0 1 0 5 3 4 3 2 1 7 5 0 1 3 2 4 3 5 7 9 0 1 3 4 2 4 2 7 9..
  • 在您的示例中,第二行与哪一天匹配
  • 令人困惑的是,您有一个从第 11 天开始的映射表,而您的 iinput 示例小于那个

标签: r dataframe


【解决方案1】:

我们可以使用data.table 中的rleid 来获得正确的“发生”

library(data.table)
wkdays <- c("Monday", "Tuesday", "Wednesday", "Thursday", 
"Friday", "Saturday", "Sunday")

out1 <-  do.call(rbind, Map(function(x, y) {
              i1 <- match(y, wkdays): length(x)
              i2 <- x[i1] != 0
              i3 <- all(i2)
              grp1 <- rleid(i2)
              Days <- if(i3) tapply(names(x)[i1][i2], grp1[i2], FUN = paste, collapse= ' ') else ''
             Occurance <- if(i3) length(grp1[i2]) else 0
             data.frame(Occurance, Days)
            }, asplit(df[-(1:3)], 1), df$Day))

 out1$Duration <- rowSums(df1[startsWith(names(df1), 'day')])
 out1
 # Occurance                               Days Duration
 #1         7 day1 day2 day3 day4 day5 day6 day7       11
 #2         0                                          12
 #3         5           day3 day4 day5 day6 day7       18

【讨论】:

    【解决方案2】:

    你可以使用leadlagdplyr

    我试过了,结果如下:

    library(dplyr)
    
    df %>% 
        select(serial, contains("day", ignore.case = FALSE)) %>% 
        group_by(serial) %>% 
        tidyr::gather(day, val, -serial) %>% 
        # convert to binary 
        mutate(occur = ifelse(val > 0, 1, 0)) %>% 
        # if detect a seq, add cumulative, else 0
        mutate(cums = ifelse(lead(occur) > 0 & lag(occur) > 0 & occur > 0, 
                             occur + cumsum(occur), 0)) %>% 
        summarise(occurance = max(cums, na.rm = T), duration = sum(val))
    
    # A tibble: 3 x 3
      serial occurance duration
       <dbl>     <dbl>    <dbl>
    1     10         6       18
    2     12         7       11
    3    123         0       12
    

    【讨论】:

    • 非常感谢,也许这是一个很大的问题,但我怎样才能返回序列天数?
    • 您可以找出最大“出现次数”在哪一行(使用which)并向后工作以检索相应的行。这是一种 hack-ish 的做法。由于您从根本上处理序列,因此我建议您将数据转换为时间序列格式并使用相关包。
    • 还有一个问题,请问如何根据 id 对结果进行分组,以便在示例输出中。基本上而不是... summarise(occurance = max(cums, na.rm = T), duration = sum(val))...我怎样才能接收到带有 id(分组)出现和持续时间的输出。谢谢你的时间
    • 你的意思是你想用序列号和ID来分组吗?直接做group_by(serial, id).
    • 是的,我确实需要 serial 和 id1 定义一个单独的观察 - 我认为我们需要为此创建一个索引
    猜你喜欢
    • 1970-01-01
    • 2022-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 2018-12-13
    相关资源
    最近更新 更多