根据给定变量识别连续的序列

7

我现在卡住了。 df1 包含以下变量:

  1. serial = 一群人

  2. id1 = 群体中的一个人 (例如,12 (serial) 1 (id1) =群体12中的第一个人;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 - 识别连续序列


这个问题看起来很像我昨天回答过的另一个问题。 - akrun
如果有列直到day796,我想知道你会认为连续的值有多少个。 - akrun
考虑一个行是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..的情况。 - akrun
在你的例子中,第二行匹配哪一天? - akrun
混淆的是,您有一个从第11天开始的映射表,而您的输入示例小于该值。 - akrun
2个回答

1
我们可以使用来自data.table的rleid来正确获取“Occurance”。
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

0
您可以使用 dplyrleadlag
我在自己的一侧尝试了它,这是结果:
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

非常感谢。也许这是一个很大的要求,但我该如何返回日期序列? - Rstudent
1
您可以使用which函数查找最大的“occurrence”所在的行,并往回追溯以检索相应行。这是一种巧妙的方法。由于您基本上正在处理序列,因此建议您将数据转换为时间序列格式并使用相关软件包。 - Thomas Jc
还有一个问题,请问我如何根据ID对结果进行分组,以便获得示例输出中的结果。基本上,我想要一个按ID(分组)出现次数和持续时间汇总的输出,而不是...summarise(occurance = max(cums, na.rm = T), duration = sum(val))...。谢谢您的时间。 - Rstudent
你的意思是想要根据serial和id进行分组吗?直接使用group_by(serial, id)即可。 - Thomas Jc
是的,我确实需要串行号和ID1来定义单个观测值 - 我认为我们需要为此创建一个索引。 - Rstudent
但是我该如何按(序列ID1)出现和持续时间排序来查看结果?目前这行代码.. mutate(cums = ifelse(lead(occur) > 0 & lag(occur) > 0 & occur > 0, occur + cumsum(occur), 0))...是基于日期排序的。 - Rstudent

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接