Как заменить строки соответствующей строкой из списка? - PullRequest
0 голосов
/ 12 декабря 2018

Скажем, у меня есть столбец df1$z с некоторыми "грязными" строками в

> df1$z
 [1] alpha uybkh   kilo-mdjfyrs  lima qxaucnpe gamma-qpnej  
 [5] beta-okmwy    beta-uybkh    gamma mdjfyrs lima qxaucnpe
 [9] beta qpnej    kilo okmwy   
9 Levels: alpha uybkh beta-okmwy beta-uybkh ... lima qxaucnpe

Некоторые строки начинаются с шаблонов, включенных в другой вектор a.

> a
[1] "alpha" "beta"  "gamma"

Эти a строки соответствия в z Я хочу заменить на соответствующий шаблон вектора a, чтобы получились следующие результаты:

# [1] "alpha"         "kilo-mdjfyrs"  "lima qxaucnpe" "gamma"        
# [5] "beta"          "beta"          "gamma"         "lima qxaucnpe"
# [9] "beta"          "kilo okmwy" 

Я написал функцию, которая приблизила меня, но он заменяет строки не сразу, и мне не удалось собрать все воедино:

> lapply(seq_along(a), function(x) {z[grep(paste0("^", a[x]), z)] <- a[x]; z})
[[1]]
 [1] "beta sfrmyijl" "lima-xudwfkm"  "lima-kirvpys"  "gamma wriygcb"
 [5] "alpha"         "alpha"         "kilo xudwfkm"  "alpha"        
 [9] "gamma wriygcb" "kilo-wvxgar"  

[[2]]
 [1] "beta"           "lima-xudwfkm"   "lima-kirvpys"   "gamma wriygcb" 
 [5] "alpha wvxgar"   "alpha-sfrmyijl" "kilo xudwfkm"   "alpha-kirvpys" 
 [9] "gamma wriygcb"  "kilo-wvxgar"   

[[3]]
 [1] "beta sfrmyijl"  "lima-xudwfkm"   "lima-kirvpys"   "gamma"         
 [5] "alpha wvxgar"   "alpha-sfrmyijl" "kilo xudwfkm"   "alpha-kirvpys" 
 [9] "gamma"          "kilo-wvxgar"   

Я также потерпел неудачу с некоторыми mapply() подходами, которые, как мне кажется, могли бы быть здесь полезными, и рассмотрелнекоторые существующие ответы, такие как этот , который я не смог приспособить к своей конкретной проблеме.

Так как бы я сделал это эффективным базовым R способом? Обратите внимание , что замена должна быть помещена обратно во фрейм данных df1, не нарушая порядок строк.

Данные

a <- c("alpha", "beta", "gamma")
set.seed(105056)
z <- paste0(sample(c(a, "kilo", "lima"), 10, replace=TRUE), 
            sample(c("-", " "), 10, replace=TRUE), 
            replicate(5, paste0(sample(letters, sample(5:9)), collapse="")))
df1 <- data.frame(z, x=rnorm(10))

Ответы [ 3 ]

0 голосов
/ 12 декабря 2018

Вы можете использовать следующее решение sub:

> sub(paste0(".*\\b(",paste(a, collapse="|"),")\\b.*"), "\\1", df1$z)
 [1] "alpha"         "kilo-mdjfyrs"  "lima qxaucnpe" "gamma"         "beta"         
 [6] "beta"          "gamma"         "lima qxaucnpe" "beta"          "kilo okmwy"

Шаблон будет соответствовать любым символам до и после ключевого слова в вашем векторе a и будет захватывать ключевое слово в группе 1, пока *Шаблон замены 1006 * сохранит только найденное ключевое слово и удалит весь текст до и после него.Если совпадений нет, изменений не будет.

См. Демонстрационную версию regex .

0 голосов
/ 12 декабря 2018

Вот несколько более длинное, но менее непрозрачное решение, использующее ifelse и grepl:

df1$z <- ifelse(grepl("alpha.*", df1$z), a[1],
            ifelse(grepl("beta.*", df1$z), a[2],
                   ifelse(grepl("gamma.*", df1$z), a[3], as.character(df1$z))))
df1
               z           x
1          alpha -0.18973111
2   kilo-mdjfyrs -0.88150363
3  lima qxaucnpe  0.01665189
4          gamma  0.62647841
5           beta -0.29526632
6           beta  0.42480082
7          gamma  1.03653486
8  lima qxaucnpe -1.51910745
9           beta  1.21504343
10    kilo okmwy  1.25321421
0 голосов
/ 12 декабря 2018

Мы могли бы использовать sub.Создайте шаблон с paste после создания одной строки из 'a', затем используйте его для захвата шаблона с обратной ссылкой (\\1) в замене

sub(paste0(".*\\b(", paste(a, collapse="|"), ")\\b.*"), "\\1", df1$z)
#[1] "alpha"         "kilo-mdjfyrs"  "lima qxaucnpe" "gamma"         "beta"          "beta"          "gamma"        
#[8] "lima qxaucnpe" "beta"          "kilo okmwy"   

ПРИМЕЧАНИЕ: sub решение былоразмещен первым здесь


Или используя str_replace из stringr

library(tidyverse)
df1 %>% 
  mutate(z = str_replace(z, 
      paste0(".*\\b(", paste(a, collapse="|"), ")\\b.*"), "\\1"))
#           z           x
#1          alpha -0.18973111
#2   kilo-mdjfyrs -0.88150363
#3  lima qxaucnpe  0.01665189
#4          gamma  0.62647841
#5           beta -0.29526632
#6           beta  0.42480082
#7          gamma  1.03653486
#8  lima qxaucnpe -1.51910745
#9           beta  1.21504343
#10    kilo okmwy  1.25321421
...