2017-10-10 101 views
4

首先,请让我知道我正在做的是不好的使用dplyr,因为我不确定我是否以最好的方式接近这个。我有以下数据框:Group_by然后用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 

我想这样做的过滤是一个有点罗嗦,但我会努力 - 我想通过删除所有行COL1 ==“0”来过滤数据框如果该行在该用户的第一行之后发生,其中col1 =='1'。 (粗体显示我搞砸了原来的问题,并切换了0和1)。例如,对于用户7,第三行有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 

我试过以下,但没有奏效。我想添加一个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 

这个输出之间的差异,以及正确的输出,是这个错误的输出也过滤原始数据帧的10行。

任何与此有关的帮助表示赞赏!

编辑 - 我特别好奇,如果group_by()%>%filter()对于dplyr来说在R中是不好的练习。我的group_by()的99%后面跟着summary(),这显然更有意义。

编辑2 - 我想我已经知道了!

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

只需翻转发生变异()和GROUP_BY的顺序()调用,并调整了发生变异()调用了一下,似乎已经得到它完成。尽管如此,我很乐意听到更好的方法。

回答

3

有一个cumany功能,这对于这些连续的病症,如:

mydf %>% 
    group_by(user) %>% 
    mutate(seen_one = cumany(col1 == "1")) %>% 
    filter(!seen_one | col1 != "0") 

也就是说标志着"1"一直在与seen_one“流”之后的所有行,然后继续行没有满足其中一个条件。 (filter的语义要求反转条件以“摆脱”行,!(A & B) == !A | !B。)

+1

高招海事组织,虽然输出显著从什么OP预计 – Aramis7d

+0

的OP也不是很一致的区别与要求,首先他说删除行col1 == 1,然后删除行12和13,其中col1 == 0. – liborm

+0

像我说的过滤是罗嗦,第二眼我把它搞砸了 – Canovice

1

这里是通过dplyr

library(dplyr) 

df %>% 
group_by(user) %>% 
mutate(id1 = row_number(), new_col = max(which(col1 == 1)+1)) %>% 
filter(!(col1 == 0 & id1 >= new_col)) 

这给出了一个想法,

# A tibble: 10 x 6 
# Groups: user [2] 
    user col1  col2 col3 id1 new_col 
    <dbl> <chr>  <dbl> <chr> <int> <dbl> 
1  7  0 0.54742608  a  1  5 
2  7  0 0.89271859  b  2  5 
3  7  1 0.48999057  c  3  5 
4  7  1 0.17163211  d  4  5 
5  7  3 0.96146770  f  6  5 
6  7 NULL 0.31368382  g  7  5 
7  8  3 0.82051455  h  1  5 
8  8  3 0.30705440  i  2  5 
9  8  0 0.18545358  j  3  5 
10  8  1 0.04834678  k  4  5 
+1

我喜欢在mutate()中创建额外列的想法,而不是有一个过于复杂的过滤器()。 mutate()%>%filter()使得过滤器更易于阅读。 – Canovice

1

可以通过更新的尝试一点点来解决:

library(dplyr) 
mydf %>% 
    group_by(user) %>% 
    filter(col1 != 0 | row_number() < which.max(col1 == 1)) 


# user col1  col2 col3 
# <dbl> <chr>  <dbl> <chr> 
# 1  7  0 0.756522673  a 
# 2  7  0 0.168314555  b 
# 3  7  1 0.977254798  c 
# 4  7  1 0.722721694  d 
# 5  7  3 0.407849378  f 
# 6  7 NULL 0.245335151  g 
# 7  8  3 0.003423735  h 
# 8  8  3 0.191716738  i 
# 9  8  0 0.626846893  j 
#10  8  1 0.546459621  k 

使用我们选择col1不等于0的所有行或当前行小于该组第一次出现的索引的行。

1

交替,建设的方向@ liborm的回答提供:

mydf %>% 
    group_by(user) %>% 
    mutate(k = cumany(col1 == '0'), j = cumany(col1 == '1')) %>% 
    filter(!(col1 == 0 & k == TRUE & j == TRUE)) %>% 
    select(-k,-j) 

回报:

user col1 col2 col3 
    <dbl> <chr> <dbl> <chr> 
1  7  0  1  a 
2  7  0  1  b 
3  7  1  0  c 
4  7  1  0  d 
5  7  3  0  f 
6  7 NULL  1  g 
7  8  3  0  h 
8  8  3  1  i 
9  8  0  1  j 
10  8  1  0  k