使用 R 总结二进制数据中的差距

Summarize Gaps in Binary Data using R

我在玩二进制数据。

我按以下方式在列中存储数据:

       A   B   C   D   E   F   G   H   I   J   K   L   M   N
       -----------------------------------------------------
       1   1   1   1   1   1   1   1   1   0   0   0   0   0
       0   0   0   0   1   1   1   0   1   1   0   0   1   0
       0   0   0   0   0   0   0   1   1   1   1   1   0   0

1 - 表示系统开启,0 表示系统关闭

我正在努力寻找方法来总结这些系统 on/off 过渡之间的差距。

例如, 对于第一行,它在 'I' 后停止工作 对于第二行,它从 'E' 到 'G' 工作,然后在 'I' 和 'M' 中再次工作,但在其他期间关闭。

有没有办法总结一下?

我希望以下面的形式看到我的结果

    row-number    Number of 1's       Range
    ------------  ------------------  ------
    1                    9             A-I
    2                    3             E-G
    2                    2             I-J
    2                    1             M
    3                    5             H-L

这是一个 tidyverse 解决方案:

library(tidyverse)
df %>%
  rowid_to_column() %>%
  gather(col, val, -rowid) %>%
  group_by(rowid) %>%
  # This counts the number of times a new streak starts
  mutate(grp_num = cumsum(val != lag(val, default = -99))) %>%
  filter(val == 1) %>%
  group_by(rowid, grp_num) %>%
  summarise(num_1s = n(),
            range = paste0(first(col), "-", last(col)))


## A tibble: 5 x 4
## Groups:   rowid [3]
#  rowid grp_num num_1s range
#  <int>   <int>  <int> <chr>
#1     1       1      9 A-I  
#2     2       2      3 E-G  
#3     2       4      2 I-J  
#4     2       6      1 M-M  
#5     3       2      5 H-L 

带有 data.table 的选项。在创建行号列 (setDT) 时将 'data.frame' 转换为 'data.table',将 melt 从 'wide' 转换为 'long' 格式,指定 id.var 作为行号列 'rn',在按 'rn' 分组的 'value' 列上创建一个 运行-lenght-id (rleid) 列,对行进行子集化其中 'value' 为 1,用行数 (.N) 和 'variable' 值的 pasted range 进行汇总,按 'grp' 和分组'rn',如有必要,通过 'rn' 将不需要的列分配给 NULLorder

library(data.table)
melt(setDT(df1, keep.rownames = TRUE), id.var = 'rn')[,
   grp := rleid(value), rn][value == 1, .(NumberOfOnes = .N,
    Range = paste(range(as.character(variable)), collapse="-")),
      .(grp, rn)][,  grp := NULL][order(rn)]
#   rn NumberOfOnes Range
#1:  1            9   A-I
#2:  2            3   E-G
#3:  2            2   I-J
#4:  2            1   M-M
#5:  3            5   H-L

或使用 base Rrle

do.call(rbind, apply(df1, 1, function(x) {
       rl <- rle(x)
       i1 <- rl$values == 1
       l1 <- rl$lengths[i1]
       nm1 <- tapply(names(x), rep(seq_along(rl$values), rl$lengths),
          FUN = function(y) paste(range(y), collapse="-"))[i1]
       data.frame(NumberOfOnes = l1, Range = nm1)}))

数据

df1 <- structure(list(A = c(1L, 0L, 0L), B = c(1L, 0L, 0L), C = c(1L, 
0L, 0L), D = c(1L, 0L, 0L), E = c(1L, 1L, 0L), F = c(1L, 1L, 
0L), G = c(1L, 1L, 0L), H = c(1L, 0L, 1L), I = c(1L, 1L, 1L), 
    J = c(0L, 1L, 1L), K = c(0L, 0L, 1L), L = c(0L, 0L, 1L), 
    M = c(0L, 1L, 0L), N = c(0L, 0L, 0L)), class = "data.frame", row.names = c(NA, 
-3L))