Search code examples
rgroup-byoutliersdplyr

How to mutate a subset of a group in r


I'm having trouble mutating my df in R. My df looks like this

df< 
      I    class part      datetime             value    indicator
     <int> <chr> <chr>   <S3: POSIXct>          <dbl>     <dbl>
1       1   A    part1  2016-12-15 10:43:08     0.12       0
2       1   A    part2  2015-11-16 13:52:07     0.15       0
3       1   A    part3  2015-11-16 15:37:27     1.20       0
4       2   A    part1  2015-11-16 15:43:03     0.78       1
5       2   A    part2  2015-11-16 16:01:03     0.14       1
6       2   A    part3  2015-11-05 07:10:02     1.40       1
...    ...  ...   ...       ...                 ...       ...

I am trying to remove the extreme outliers for part 1 in the group indicator (0 or 1)

I tried this

    remove_outliers <- function(x, na.rm = TRUE, ...) {
      qnt <- quantile(x, probs=c(.25, .75), na.rm = na.rm, ...)
      H <- 3.0 * IQR(x, na.rm = na.rm)
      y <- x
      y[x < (qnt[1] - H)] <- NA
      y[x > (qnt[2] + H)] <- NA
      y
    }

dfNew <- df %>%
  group_by(indicator, part) %>% 
  mutate(value = remove_outliers(value[part="part1"])) %>%
  ungroup()

this removes all of the values. How can i remove the extreme outliers within the group indicator for only part1?


Solution

  • 2 errors in your code value[part="part1"] should have a "==" not a "=" and is misplaced because value[part=="part1"] is shorter than value. You need to subset at the beginning of your treatment

    dfNew  <- subset(df,part=="part1") %>%
      group_by(indicator, part) %>% 
      mutate(value = remove_outliers(value)) %>%
      ungroup()
    

    To get the whole dataset and not only the subset as a result

    mutate_cond <- function(.data, condition, ..., envir = parent.frame()) {
      condition <- eval(substitute(condition), .data, envir)
      .data[condition, ] <- .data[condition, ] %>% mutate(...)
      .data
    }
    
    dfNew =df %>%
      group_by(indicator, part) %>% 
      mutate_cond(part=="part1",value = remove_outliers(value)) %>%
      ungroup()
    

    It works for me after this modification