The approach seems valid overall, but can be simplified since parse_number() already removes any non-string characters.
To apply it to many columns, you can simply put the operations in a function that you call with across().
You don't provide data to test, I would expect something like that to work:
library(tidyverse)
df <- data.frame(col1=c(1,4,7,2,"<56",8,3,8,"<10",7,2),
col2=c(65,"<7",1,5,"<99",3,6,8,876,"<34",1))
process_numbers <- function(x){
if_else(str_detect(x, "^<"),
parse_number(x)/2,
parse_number(x))
}
df %>%
mutate(across(col1:col2, process_numbers))
#> col1 col2
#> 1 1 65.0
#> 2 4 3.5
#> 3 7 1.0
#> 4 2 5.0
#> 5 28 49.5
#> 6 8 3.0
#> 7 3 6.0
#> 8 8 8.0
#> 9 5 876.0
#> 10 7 17.0
#> 11 2 1.0
Created on 2020-12-21 by the reprex package (v0.3.0)
Of course you can consider using round() or floor() to have only integer results.