选择每组连续 1 的行

Select rows per group with consecutive 1s

提问人:mto23 提问时间:8/17/2023 最后编辑:mto23 更新时间:8/17/2023 访问量:59

问:

我有一个数据帧,我想通过仅选择连续值“1”来对其进行子集。

具体来说,我有一个数据帧,如下所示:

library(tidyverse)
library(zoo)

df <- data.frame(matrix(ncol = 3, nrow = 17))
colnames(df) <- c("row_id","id", "k_yes")
df$row_id <- c(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17)
df$id <- c("1_1","1_1","1_1","1_1","1_1","1_1","1_2","1_2","1_2","1_2","1_2","1_2","1_3","1_3","1_3","1_3","1_3")
df$k_yes <- c(1,1,1,0,1,1,0,0,0,1,1,0,1,0,1,0,1)
df
   row_id    id  k_yes
1       1   1_1      1
2       2   1_1      1
3       3   1_1      1
4       4   1_1      0
5       5   1_1      1
6       6   1_1      1
7       7   1_2      0
8       8   1_2      0
9       9   1_2      0
10     10   1_2      1
11     11   1_2      1
12     12   1_2      0
13     13   1_3      1
14     14   1_3      0 
15     15   1_3      1
16     16   1_3      0
17     17   1_3      1

我想创建两个数据集

1) 一个,每个组 () 只有“1”,但总是两个或两个以上连续。因此,如果两个“1”之间有一个“0”,至少应该丢弃最后一个“1”。因此,它将接受诸如 、 、 依此类推,但不是 或id1-11-1-10-1-11-1-1-0

然后,我还希望添加一列以了解已形成的新组/序列,因为它并不总是与 id 相同(如果 id 中有两个子组/序列)。基本上,对于整个数据帧,此列的每个序列都应该有一个唯一的代码(现在,我只是用一个字母绑定了 id,但它可以是一个连续的数字/字母,例如)

此数据帧如下所示:

  row_id    id k_yes  new_group
1      1   1_1     1      1_1_A
2      2   1_1     1      1_1_A
3      3   1_1     1      1_1_A
4      5   1_1     1      1_1_B
5      6   1_1     1      1_1_B
6     10   1_2     1      1_2_A
7     11   1_2     1      1_2_A

2) 另一个,每组 () 接受“1”之间的一个“0”,但如果“0”之后没有其他“1”,则不接受。 因此,它将接受诸如 、 、 、 等的序列,但不接受 or or 之类的序列(在后者中,它只会保留前 1 个)。“new_group”列与之前相同。id1-0-11-1-0-11-1-0-1-11-1-0-1-0-10-1-11-1-01-1-0-0-1

df 的预期输出为:

   row_id    id k_yes  new_group
1       1   1_1     1      1_1_A
2       2   1_1     1      1_1_A
3       3   1_1     1      1_1_A
4       4   1_1     0      1_1_A
5       5   1_1     1      1_1_A
6       6   1_1     1      1_1_A
7      10   1_2     1      1_2_A
8      11   1_2     1      1_2_A
9      12   1_3     1      1_3_A
10     14   1_3     0      1_3_A
11     15   1_3     1      1_3_A
12     16   1_3     0      1_3_A
13     17   1_3     1      1_3_A

在本例中,id “1_1” 仅获取“新组”(1_1_A) 的一个值,因为它都是相同的序列(包括 0)

我尝试遵循这个答案,但没有成功,因为我尝试过:

> df |>
     group_by(id) |> 
     mutate(b = c(first(k_yes) , zoo::rollsum(k_yes, 1))) |>
     summarise(groups_to_keep = id[which(b >= 2)]) -> gk

Error in `mutate()`:
ℹ In argument: `b = c(first(k_yes), zoo::rollsum(k_yes, 1))`.
ℹ In group 1: `id = "1_1"`.
Caused by error:
! `b` must be size 5 or 1, not 6.

我认为问题出在功能上,但是在检查了帮助页面后,我仍然不清楚应该如何应用此功能。rollsum()

任何帮助都是值得赞赏的!

更新:

我添加了一个新版本的数据集,它将在第一个数据集 (1) 中为“新组”创建两个值。

R 选择 DPLYR 序列 动物园

评论


答:

1赞 Mark 8/17/2023 #1

对于数据集 #1:

df |>
  filter(k_yes & (lag(k_yes) | lead(k_yes)), .by = id) |>
  mutate(new_group = row_number() == 1 | row_id - 1 != lag(row_id), .by = id) |>
  mutate(new_group = paste0(id, "_", LETTERS[cumsum(new_group)]), .by = id)

数据集 2:

df |>
  filter(k_yes | (!k_yes & lag(k_yes) & lead(k_yes)), .by = id) |> 
  mutate(new_group = row_number() == 1 | row_id - 1 != lag(row_id), .by = id) |>
  mutate(new_group = paste0(id, "_", LETTERS[cumsum(new_group)]), .by = id)

评论

0赞 mto23 8/17/2023
多谢!这有帮助,但仅适用于数据集 1 - 对数据集 2 有什么想法吗?我也忘记了我想添加一个新列来标识新组(请参阅问题中的编辑),关于如何将其包含在您提供的代码中的任何想法?
1赞 Mark 8/17/2023
@mto23更新:-)
1赞 Mark 8/17/2023
两个问题:1.您说的是数据集 1 还是 2?2.输出应该是什么?(添加问题,请不要在评论中! :-)
1赞 mto23 8/17/2023
我的错!我现在用新的示例和输出编辑了这个问题。关于第一个问题,在我提供的示例中,它只会影响数据集 1,但它也适用于数据集 2。谢谢!!
1赞 mto23 8/17/2023
现在工作得很好,非常感谢!!:)