2017-10-10 98 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