Group_by 然后用 dplyr 过滤

Can*_*ice 5 r dplyr

首先,请让我知道我正在做的事情是否对 dplyr 使用不当,因为我不确定我是否以最好的方式来解决这个问题。我有以下数据框:

mydf = data.frame(user = c(7,7,7,7,7,7,7,8,8,8,8,8,8),
                  col1 = c('0','0','1','1','0','3','NULL','3','3','0','1','0','0'),
                  col2 = runif(n=13),
                  col3 = letters[1:13], 
                  stringsAsFactors = FALSE)

> mydf
   user col1      col2 col3
1     7    0 0.7607907    a
2     7    0 0.1580448    b
3     7    1 0.8063540    c
4     7    1 0.7331512    d
5     7    0 0.2433631    e
6     7    3 0.2357065    f
7     7 NULL 0.4864172    g
8     8    3 0.6806089    h
9     8    3 0.2229874    i
10    8    0 0.6187911    j
11    8    1 0.7617177    k
12    8    0 0.5884821    l
13    8    0 0.4985750    m
Run Code Online (Sandbox Code Playgroud)

我想做的过滤有点罗嗦,但我会尝试 - 我想通过删除col1 == '0' 的所有行来过滤数据框,如果该行发生在该用户的第一行之后,其中col1 = = '1'。(粗体表示我搞砸了原来的问题,并切换了 0 和 1)。

例如,对于用户 7,第 3 行的 col1 == '1',所以我想过滤第 3 行之后的所有行,其中 col1 == '0'(在这种情况下,只有第 5 行)。然后,对于用户 8,第 11 行是该用户的第一行,其中 col1 == '1',因此我想过滤第 12 行和第 13 行,因为 col1 == '0'。

我的最终输出应该是这样的:

> mydf
   user col1      col2 col3
1     7    0 0.7607907    a
2     7    0 0.1580448    b
3     7    1 0.8063540    c
4     7    1 0.7331512    d
6     7    3 0.2357065    f
7     7 NULL 0.4864172    g
8     8    3 0.6806089    h
9     8    3 0.2229874    i
10    8    0 0.6187911    j
11    8    1 0.7617177    k
Run Code Online (Sandbox Code Playgroud)

我尝试了以下方法,但没有奏效。我想添加一个 rownums 列,然后按用户分组,然后过滤我所描述的工作方式。我的想法是我的过滤器调用有问题:

mydf %>%
  mutate(rownums = 1:nrow(mydf)) %>%
  group_by(user) %>%
  filter(!(col1 == "0" & rownums > min(which(col1 == "1"))))

# A tibble: 9 x 5
# Groups:   col0 [2]
   user  col1      col2  col3 rownums
  <dbl> <chr>     <dbl> <chr>   <int>
1     7     0 0.2088034     a       1
2     7     0 0.2081894     b       2
3     7     1 0.1825428     c       3
4     7     1 0.2143353     d       4
5     7     3 0.1979774     f       6
6     7  NULL 0.2990799     g       7
7     8     3 0.7808038     h       8
8     8     3 0.1694272     i       9
9     8     1 0.1526450     k      11
Run Code Online (Sandbox Code Playgroud)

此输出与正确输出之间的区别在于,此输出也错误地过滤了原始数据帧的第 10 行。

对此的任何帮助表示赞赏!

编辑 - 我特别好奇 group_by() %>% filter() 是否在 R 中对于 dplyr 是不好的做法。我的 group_by() 的 99% 后面是 summarise(),这显然更有意义。

EDIT2 - 我想我明白了!

mydf %>%
  group_by(col0) %>%
  mutate(rownums = 1:length(col0)) %>%
  filter(!(col1 == "0" & rownums > min(which(col1 == "1"))))
Run Code Online (Sandbox Code Playgroud)

简单地翻转 mutate() 和 group_by() 调用的顺序,并稍微调整 mutate() 调用,看起来已经完成了。不过,我愿意听取更好的方法。

lib*_*orm 4

有一个cumany函数对于这些顺序条件很有用,如下所示:

mydf %>%
  group_by(user) %>% 
  mutate(seen_one = cumany(col1 == "1")) %>%
  filter(!seen_one | col1 != "0")
Run Code Online (Sandbox Code Playgroud)

即用 标记已"1"进入“流”中的所有行seen_one,然后保留不满足其中一个条件的行。(filter需要反转条件以“删除”行的语义!(A & B) == !A | !B。)