R - замена части строки на цикл for и gsub - PullRequest
0 голосов
/ 28 февраля 2019

У меня есть два фрейма данных (df1 и df2), и я хочу заменить часть строк в df1 соответствующей строкой в ​​df2.

Например: результат должен быть df3

a <- c("extra text test-ID 1", "extra text test-ID 2", "extra text test-ID 3", "extra text test-ID 4")
b <- c("experiment 5","experiment 6","experiment 7","experiment 8") 
c <- c("exercise 9","exercise 10","exercise 11","exercise 12")

df1 <- data.frame(a,b,c)
names(df1) <- c('a','b','c')

d <- c("test-ID 1", "test-ID 2", "test-ID 4")
e <- c("test-ID 1098", "test-ID 245", "test-ID 77")

df2 <- data.frame(d,e)
names(df2) <- c('a','b')

df1
df2

f <- c("extra text test-ID 1098", "extra text test-ID 245", "extra text test-ID 3", "extra text test-ID 77")
g <- c("experiment 5","experiment 6","experiment 7","experiment 8") 
h <- c("exercise 9","exercise 10","exercise 11","exercise 12")

df3 <- data.frame(f,g,h)
names(df3) <- c('a','b','c')
df3

Я хочу выполнить это с помощью функции.

replacefunction <- function(x) {
  cat(paste("searching for ", x, "\n"))
  for (i in seq_along(df2$a)) {
    old <- df2$a[i]
    new <- df2$b[i]
    if (grepl(old, x)) { 
      cat(paste0('found ', '"', old, '"', "\n"))
      return(gsub(old, new, x))
    }
  }
}

Однако это выдает предупреждение:

df4 <- replace_values(df1$a)

Warning message:
In if (grepl(old, x)) { :
  the condition has length > 1 and only the first element will be used

Изменяется только первая запись в столбце df1 $ a, почему это происходит?

1 Ответ

0 голосов
/ 28 февраля 2019

Вот один базовый подход R, в основном основанный на apply функциях.Мне почти нравится мой ответ, за исключением того, что мне пришлось прибегнуть к использованию явного цикла for внутри самого внутреннего вызова sapply.Этот цикл выполняет итерацию по всем строкам вашего df2 фрейма данных шаблона / замены и пытается выполнить замены для каждого элемента фрейма входных данных df1.

d <- c("test-ID 1", "test-ID 2", "test-ID 4")
d <- paste0("\\b", d, "\\b")
e <- c("test-ID 1098", "test-ID 245", "test-ID 77")

df2 <- data.frame(d,e)
names(df2) <- c('a','b')

df1
df1[] <- lapply(df1, function(x) {    # apply function(x) to each element of df1
    sapply(x, function(y) {
        for (i in 1:nrow(df2)) {
            y <- gsub(df2[i, "a"], df2[i, "b"], y)
        }
        return(y)
    })
})

df1

                     a            b           c
1 extra text test-ID 1 experiment 5  exercise 9
2 extra text test-ID 2 experiment 6 exercise 10
3 extra text test-ID 3 experiment 7 exercise 11
4 extra text test-ID 4 experiment 8 exercise 12
                        a            b           c
1 extra text test-ID 1098 experiment 5  exercise 9
2  extra text test-ID 245 experiment 6 exercise 10
3    extra text test-ID 3 experiment 7 exercise 11
4   extra text test-ID 77 experiment 8 exercise 12

Я использую sub для обработкилогика замены, и так как это работает с шаблонами регулярных выражений, я окружил ваши целевые шаблоны границами слов.То есть я сопоставляю \btest-ID 1\b, а не просто test-ID 1, последний из которых также будет соответствовать этому термину, если он встречается в качестве подстроки в каком-либо другом тексте.

...