A reproducible example, called a reprex is always a good idea and I see my problem, which is that I assumed you were working with with a single column and filter takes the whole row.
So, mutate will do the job
library(dplyr)
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
df <- data.frame(
zone_1 = rpois(10, 5),
zone_2 = rpois(10, 5),
zone_3 = rpois(10, 5)
)
df
#> zone_1 zone_2 zone_3
#> 1 8 5 7
#> 2 9 3 3
#> 3 7 6 8
#> 4 4 5 5
#> 5 4 5 7
#> 6 6 6 2
#> 7 7 8 1
#> 8 6 5 4
#> 9 8 11 6
#> 10 3 3 3
df %>%
mutate(zone_1 = ifelse(zone_1 < 5, NA, zone_1)) %>%
mutate(zone_2 = ifelse(zone_2 < 5, NA, zone_2)) %>%
mutate(zone_3 = ifelse(zone_3 < 5, NA, zone_2))
#> zone_1 zone_2 zone_3
#> 1 8 5 5
#> 2 9 NA NA
#> 3 7 6 6
#> 4 NA 5 5
#> 5 NA 5 5
#> 6 6 6 NA
#> 7 7 8 NA
#> 8 6 5 NA
#> 9 8 11 11
#> 10 NA NA NA
I agree with technocrat, changing your data to character is not a good idea but if you just want to do this for printing or visualization, then this is a shorter way.