4

I have the following dataset

structure(list(a = c(2, 1, 9, 2, 9, 8), b = c(4, 5, 1, 9, 12, 
NA), c = c(50, 34, 77, 88, 33, 60)), class = "data.frame", row.names = c(NA, 
-6L))

  a  b  c
1 2  4 50
2 1  5 34
3 9  1 77
4 2  9 88
5 9 12 33
6 8 NA 60

From column b I only want values between 4-9. Column c between 50-80. Replacing the values outside the range with NA, resulting in

structure(list(a = c(2, 1, 9, 2, 9, 8), b = c(4, 5, NA, 9, NA, 
NA), c = c(50, NA, 77, NA, NA, 60)), class = "data.frame", row.names = c(NA, 
-6L))

  a  b  c
1 2  4 50
2 1  5 NA
3 9 NA 77
4 2  9 NA
5 9 NA NA
6 8 NA 60

I've tried several things with replace_with_na_at function where this seemed most logical:

test <- replace_with_na_at(data = test, .vars="c",
                          condition = ~.x < 2 & ~.x > 2)

However, nothing I tried works. Does somebody know why? Thanks in advance! :)

Maya
  • 579
  • 3
  • 12
  • 3
    `replace_with_na_at()` comes from what package? You should include the relevant library call in your reproducible example. – s_baldur Jun 02 '20 at 10:33

5 Answers5

4

Yet another base R solution, this time with function is.na<-

is.na(test$b) <- with(test, b < 4 | b > 9)
is.na(test$c) <- with(test, c < 50 | c > 80)

A package naniar solution with a pipe could be

library(naniar)
library(magrittr)

test %>%
  replace_with_na_at(
    .vars = 'b',
    condition = ~(.x < 4 | .x > 9)
  ) %>%
  replace_with_na_at(
    .vars = 'c',
    condition = ~(.x < 50 | .x > 80)
  )
Rui Barradas
  • 70,273
  • 8
  • 34
  • 66
3

You simply could use Map to replace your values with NA.

dat[2:3] <- Map(function(x, y) {x[!x %in% y] <- NA;x}, dat[2:3], list(4:9, 50:80))
dat
#   a  b  c
# 1 2  4 50
# 2 1  5 NA
# 3 9 NA 77
# 4 2  9 NA
# 5 9 NA NA
# 6 8 NA 60

Data:

dat <- structure(list(a = c(2, 1, 9, 2, 9, 8), b = c(4, 5, 1, 9, 12, 
NA), c = c(50, 34, 77, 88, 33, 60)), class = "data.frame", row.names = c(NA, 
-6L))
jay.sf
  • 60,139
  • 8
  • 53
  • 110
3

You can subset with a logical vector testing your conditions.

x$b[x$b < 4 | x$b > 9] <- NA
x$c[x$c < 50 | x$c > 80] <- NA
x
#  a  b  c
#1 2  4 50
#2 1  5 NA
#3 9 NA 77
#4 2  9 NA
#5 9 NA NA
#6 8 NA 60

Data:

x <- structure(list(a = c(2, 1, 9, 2, 9, 8), b = c(4, 5, 1, 9, 12, 
NA), c = c(50, 34, 77, 88, 33, 60)), class = "data.frame", row.names = c(NA, 
-6L))
GKi
  • 37,245
  • 2
  • 26
  • 48
3

We can use map2

library(purrr)
library(dplyr)
df1[c('b', 'c')] <- map2(df1 %>% 
       select(b, c), list(c(4, 9), c(50,80)), ~ 
           replace(.x, .x < .y[1]|.x > .y[2], NA))
akrun
  • 874,273
  • 37
  • 540
  • 662
2

You should mention the packages you are using. From googling, i'm guessing you are using naniar. The problem appears to be that you did not properly specify the condition, but the following should work:

library(naniar)

test <- structure(list(a = c(2, 1, 9, 2, 9, 8), 
                    b = c(4, 5, 1, 9, 12, NA),
                    c = c(50, 34, 77, 88, 33, 60)), 
               class = "data.frame", 
               row.names = c(NA, -6L)) 

replace_with_na_at(test, "c", ~.x < 50 | .x > 80)
#>   a  b  c
#> 1 2  4 50
#> 2 1  5 NA
#> 3 9  1 77
#> 4 2  9 NA
#> 5 9 12 NA
#> 6 8 NA 60

Created on 2020-06-02 by the reprex package (v0.3.0)

shs
  • 3,683
  • 1
  • 6
  • 34