Заменить несколько слов одним словом - PullRequest
2 голосов
/ 10 октября 2019

Я хочу заменить несколько букв / слов одной буквой / словом, несколько раз в кадре данных. Например,

Некоторые данные:

df = data.frame(
      a = 1:8, 
      b = c("colour1 o", "colour2 O", "colour3 out",  "colour4 Out", 
            "soundi i", "soundr I", "sounde in", "soundw In"))

df
  a           b
1 1   colour1 o
2 2   colour2 O
3 3   colour3 out
4 4   colour4 Out
5 5    soundi i
6 6    soundr I
7 7    sounde in
8 8    soundw In

Вот что я хочу заменить на:

df_repl <- list(
  O = c("o", "out", "Out"),
  In = c("i", "in", "I")) 

Итак, в df$b o, out и Out должны стать O, а i, in и I станут In, но только если они отделены от любых других слов пробелом, поэтому o в colourне с большой буквы.

Это дает мне половину пути, но я думаю, что мне нужен еще один вложенный цикл for для перемещения через df_repl ...

for (word in df_repl[[1]]){
  patt <- paste0('\\b', word, '\\b')
  repl <- paste(names(df_repl[1]))
  df$b <- gsub(patt, repl, df$b)
}

df
  a         b
1 1 colour1 O
2 2 colour2 O
3 3 colour3 O
4 4 colour4 O
5 5  soundi i
6 6  soundr I
7 7  sounde in
8 8  soundw In

Выше o, out иOut становится O, но i, in и I не изменяются, вот желаемый результат:

  a         b
1 1 colour1 O
2 2 colour2 O
3 3 colour3 O
4 4 colour4 O
5 5  soundi In
6 6  soundr In
7 7  sounde In
8 8  soundw In

В реальных данных есть намного больше, чем два слова замены/ letters, так что я не могу просто снова запустить цикл for. Я не привязан к циклическому решению, но желательно с использованием базы R, любые предложения очень ценятся.

РЕДАКТИРОВАТЬ

Попытка уточнить мой вопрос:

Всякий раз, когда в df$b встречается один из o, out или OutЯ хочу заменить его на O

Всякий раз, когда один из i, in или I встречается в df$b Я хочу заменить его на In

Iможно получить желаемый результат, например:

for (word in df_repl[[1]]){
  patt <- paste0('\\b', word, '\\b')
  repl <- paste(names(df_repl[1]))
  df$b <- gsub(patt, repl, df$b)
}

for (word in df_repl[[2]]){
  patt <- paste0('\\b', word, '\\b')
  repl <- paste(names(df_repl[2]))
  df$b <- gsub(patt, repl, df$b)
}

Но в моем реальном наборе данных df_repl имеет длину 50, а не две, поэтому я не хочу копировать / вставлять / редактировать / перезапускать цикл for 50 раз

Ответы [ 3 ]

1 голос
/ 10 октября 2019

Это еще одно решение:

library(stringr)
in1 <- str_split(df$b, " ", simplify = TRUE)[,1]
in2 <- str_split(df$b, " ", simplify = TRUE)[,2]

in2[in2 %in% c("o", "out", "Out")] <- "O"
in2[in2 %in% c("i", "in", "I")] <- "In"
df$b <- paste(in1, in2, sep=" ") 
df

Если у вас длинный список слов в ваших данных, вы также можете переместить c(word list) за пределы:

in1<- str_split(df$b, " ", simplify = TRUE)[,1]
in2<- str_split(df$b, " ", simplify = TRUE)[,2]
o <- c("o", "Out", "Out")
i <- c("i", "in", "I") 
in2[in2 %in% o] <- "O"
in2[in2 %in% i] <- "In"
df$b <- paste(in1, in2, sep=" ") 
df

> df
  a         b
1 1 colour1 O
2 2 colour2 O
3 3 colour3 O
4 4 colour4 O
5 5 soundi In
6 6 soundr In
7 7 sounde In
8 8 soundw In
1 голос
/ 10 октября 2019

Вы можете пропустить цикл над словами в df_repl, вставив их с помощью | (или) между словами вроде:

for(i in names(df_repl)) {
    df$b <- sub(paste(paste0("\\b",df_repl[[i]],"\\b"), collapse = "|")
                , i, df$b)
}
df
#  a         b
#1 1 colour1 O
#2 2 colour2 O
#3 3 colour3 O
#4 4 colour4 O
#5 5 soundi In
#6 6 soundr In
#7 7 sounde In
#8 8 soundw In
1 голос
/ 10 октября 2019

Вы можете попробовать использовать три отдельных вызова для sub:

df$b <- sub("\\bo\\b", "i", df$b)
df$b <- sub("\\bout\\b", "in", df$b)
df$b <- sub("\\bOut\\b", "I", df$b)

df

  a          b
1 1  colour1 i
2 2  colour2 O
3 3 colour3 in
4 4  colour4 I
5 5   soundi i
6 6   soundr I
7 7  sounde in
8 8  soundw In

Чтобы автоматизировать это, вы можете попробовать использовать sapply с индексом:

terms_in <- c("o", "out", "Out")
pat <- paste0("\\b", terms_in, "\\b")
replace <- c("i", "in", "I")
sapply(seq_along(pat), function(x) {
    df$b <<- sub(pat[x], replace[x], df$b)
})
...