![](/img/trans.png)
[英]Filter in group_by + mutate not working as in group_by + summarise in dplyr R
[英]Group_by then filter with 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
我想做的過濾有點羅嗦,但我會嘗試 - 我想通過刪除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
我嘗試了以下,但它沒有用。 我想添加一個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()在R中與dplyr有關。 99%的group_by()之后是summary(),這顯然更有意義。
EDIT2 - 我想我已經擁有了!
mydf %>%
group_by(col0) %>%
mutate(rownums = 1:length(col0)) %>%
filter(!(col1 == "0" & rownums > min(which(col1 == "1"))))
只需翻轉mutate()和group_by()調用的順序,並稍微調整mutate()調用,看起來已經完成了。 我很樂意聽到一個更好的方法。
有一個cumany
函數,它對這些順序條件很有用,如下所示:
mydf %>%
group_by(user) %>%
mutate(seen_one = cumany(col1 == "1")) %>%
filter(!seen_one | col1 != "0")
這標志着"1"
之后的所有行都在帶有seen_one
的'stream'中,然后將行保留在其中一個條件不滿足的位置。 ( filter
語義要求將條件反轉為“擺脫”行, !(A & B) == !A | !B
。)
這是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
可以通過稍微更新您的嘗試來解決:
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
使用filter
我們選擇col1
不等於0的所有行或當前行小於該組的第一次出現的索引的那些行。
或者,在@ 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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.