Loop to Replace Characters in a String/Factor Variable/Vector in R

Viewed 392

I have a column that basically looks like the following set of strings:

v <- c("1 - IOP A", "1 - PHP B", "1 - RES C", "2 - IOP A", "2 - PHP B", "18 - IOP A", "18 - PHP A", "18 - RES D")

All of these are or will become factors. There are almost 300 of them in my data set. My goal is to combine the levels into categories represented by only the alpha portion of these otherwise alpha-numeric strings. From the example above, the desired output would want would be:

c("IOP A", "PHP B", "RES C", "PHP A", "RES D")

This is what I tried, but it doesn't work, provides no error message, nothing changes, and I'm not sure why or therefore what to do next/what's wrong. I'm assuming it has to do with using the loop index in the string pattern argument, but I don't know how to tell the program to use the index value.

for (i in 1:18) {
    sub(pattern = "i - ", replacement = "", v)
}

I would appreciate anyone showing me the most elegant or even multiple ways of accomplishing this as it's a pretty fundamental data engineering task. I'm sure there's an even faster sapply way to write this code, too.

Thanks :)

4 Answers

You can remove everything till "-" and take the unique values.

unique(sub('.*-\\s', '', v))
#[1] "IOP A" "PHP B" "RES C" "PHP A" "RES D"

Or similar to your attempt, taking \\d as a placeholder for numbers.

unique(sub('\\d+ - ', '', v))

You would not need sapply or for loop here since sub/gsub are vectorized so they work on vectors directly.

I can suggest an approach here with strsplit, which does not even use regex:

unique(sapply(v, function(x) strsplit(x, " - ")[[1]][2]))

[1] "IOP A" "PHP B" "RES C" "PHP A" "RES D"

The idea is to just retain the portion of the string which comes after the space-hyphen-space separator.

Data:

v <- c("1 - IOP A", "1 - PHP B", "1 - RES C", "2 - IOP A", "2 - PHP B", "18 - IOP A",
       "18 - PHP A", "18 - RES D")

Here are a couple of alternative solutions using functions from stringr package.

library(stringr)
library(magrittr)
# data
v <- c("1 - IOP A", "1 - PHP B", "1 - RES C", "2 - IOP A", "2 - PHP B", "18 - IOP A", "18 - PHP A", "18 - RES D")
# solution 1
str_remove(str_extract(v, pattern = "(?>-).*"), "-") %>% str_trim()

#[1] "IOP A" "PHP B" "RES C" "IOP A" "PHP B" "IOP A" "PHP A" "RES D"

There is another solution which uses str_replace function twice. Probably this could be improved by using it only once.

# solution 2
v <- c("1 - IOP A", "1 - PHP B", "1 - RES C", "2 - IOP A", "2 - PHP B", "18 - IOP A", "18 - PHP A", "18 - RES D")
v1 <- str_replace_all(v, pattern = "([0-9])", replacement = " ")
v2 <- str_replace(v1, pattern = "-", replacement = "")
v2 %>% str_trim()
#[1] "IOP A" "PHP B" "RES C" "IOP A" "PHP B" "IOP A" "PHP A" "RES D"

Using str_remove from stringr

library(stringr)
unique( str_remove(v, "\\d+\\s*-\\s*"))
#[1] "IOP A" "PHP B" "RES C" "PHP A" "RES D"
Related