How to delete certain condition from data frame

Viewed 61

Lets say this is my df :

people <- c(1,1,1,2,2,3,3,4,4,5,5)
activity <- c(1,1,1,2,2,3,4,5,5,6,6)
completion <- c(0,0,1,0,1,1,1,0,0,0,1)

And I would like to remove all people that never completed any activity.

I have tried this code, but somehow it does not work. I have no idea what could be wrong here.

nevercompleted<- df %>% 
  filter(completion != 0) %>% 
  group_by(people) %>% 
  summarise("frequency activity" = n())

df<- -c (df$nevercompleted)

So, in this scenario person 4 should be removed from the df. Note that I am only intrested in removing those that never completed anything like person 4, not person 1 who at one point completes an activity.

4 Answers

1. Base R

In base R, the following can easily be rewritten as a one-liner.

i <- ave(as.logical(df$completion), df$people, FUN = function(x) any(x != 0, na.rm = TRUE))
df <- df[which(i), ]
df
#   people activity completion
#1       1        1          0
#2       1        1          0
#3       1        1          1
#4       2        2          0
#5       2        2          1
#6       3        3          1
#7       3        4          1
#10      5        6          0
#11      5        6          1

2. Package dplyr

And here is a dplyr way.

First filter only people that have completed an activity, then join with the original data set in order to get all columns.

df <- df %>%
  group_by(people) %>%
  summarise(completion = any(as.logical(completion))) %>%
  filter(completion) %>%
  select(-completion) %>%
  left_join(df, by = 'people')

df
#`summarise()` ungrouping output (override with `.groups` argument)
## A tibble: 9 x 3
#  people activity completion
#   <dbl>    <dbl>      <dbl>
#1      1        1          0
#2      1        1          0
#3      1        1          1
#4      2        2          0
#5      2        2          1
#6      3        3          1
#7      3        4          1
#8      5        6          0
#9      5        6          1

Data

In the question there is no data.frame instruction, only the creation of the column vectors.

people <- c(1,1,1,2,2,3,3,4,4,5,5)
activity <- c(1,1,1,2,2,3,4,5,5,6,6)
completion <- c(0,0,1,0,1,1,1,0,0,0,1)
df <- data.frame(people, activity, completion)

in Base we could do this

    byGroup <- split(df,df$people)
    do.call(rbind,byGroup[sapply(byGroup, function(x) !all(x$completion == 0))])

      people activity completion
1.1       1        1          0
1.2       1        1          0
1.3       1        1          1
2.4       2        2          0
2.5       2        2          1
3.6       3        3          1
3.7       3        4          1
5.10      5        6          0
5.11      5        6          1

can be done this way

library(tidyverse)
df <- tibble(people, activity, completion)

df %>% 
  group_by(people) %>% 
  filter(any(completion != 0))

# A tibble: 9 x 3
# Groups:   people [4]
  people activity completion
   <dbl>    <dbl>      <dbl>
1      1        1          0
2      1        1          0
3      1        1          1
4      2        2          0
5      2        2          1
6      3        3          1
7      3        4          1
8      5        6          0
9      5        6          1

Here's the code that should work:

library(dplyr)

people <- c(1,1,1,2,2,3,3,4,4,5,5)
activity <- c(1,1,1,2,2,3,4,5,5,6,6)
completion <- c(0,0,1,0,1,1,1,0,0,0,1)

df <- data.frame(people, activity, completion)

df <- filter(df, completion != 0)

Result:

  people activity completion
1      1        1          1
2      2        2          1
3      3        3          1
4      3        4          1
5      5        6          1

This will filter your dataframe to rows whose completion variable is not 0.

I'm not sure where you were going with the group_by and summarize. If you want to do more than remove the rows whose completion variable is 0, please clarify that in your question.

Related