Заменить все слово или слова с частичным совпадением в R - PullRequest
2 голосов
/ 19 апреля 2020

У меня есть фрейм данных с тысячами названий городов с ошибками. Мне нужно исправить это и не могу найти решение, хотя я много искал. Я попробовал несколько функций и подходов

Это миниатюрный образец данных:

citA <- data.frame("num" = c(1,2,3,4,5,6,7,8),
               "city" = c("BORNE","BOERNAE","BARNE","BOERNE",
                          "GALDEN","GELDON","GOELDEN","GOLDEN"))

   num    city
1   1   BORNE
2   2 BOERNAE
3   3   BARNE
4   4  BOERNE
5   5  GALDEN
6   6  GELDON
7   7 GOELDEN
8   8  GOLDEN

Это некоторые из функций, которые я пробовал, пробовал еще много, включая str_replace и str_detect :

cit <- function(x){
  ifelse(x %in% grepl(c("BOR","BOE","BAR")),"BOERNE",
         ifelse(x %in% grepl(c("GAL","GEL","GOE")), "GOLDEN", "OTHER"))
}

Или

cit <- function(x){
  ifelse(x %in% c("BOR","BOE","BAR"),"BOERNE",
         ifelse(x %in% c("GAL","GEL","GOE"), "GOLDEN", "OTHER"))
}

Код запуска:

`citA$city2 <- cit(citA$city)`

Неверный результат:

  num    city city2
1   1  BOERNE OTHER
2   2 BOERNAE OTHER
3   3   BARNE OTHER
4   4  BOERNE OTHER
5   5  GALDEN OTHER
6   6  GELDON OTHER
7   7 GOELDEN OTHER
8   8  GOLDEN OTHER

Также попытался:

citA$city[grepl(c("BOR","BOE","BAR"),citA$city)] <- "BOERNE" 

Но это выдает ошибку:

Warning message:
In grepl(c("BOR", "BOE", "BAR"), citA$city) :
  argument 'pattern' has length > 1 and only the first element will be used

Ваши идеи будут очень полезны!

Ответы [ 3 ]

0 голосов
/ 19 апреля 2020

Если у вас много таких шаблонов, вы можете использовать case_when из dplyr:

library(dplyr)
library(stringr)

citA %>%
  mutate(city2 = case_when(str_detect(city, 'BOR|BOE|BAR') ~ 'BOERNE', 
                           str_detect(city, 'GAL|GEL|GOE|GOL') ~ 'GOLDEN',
                           TRUE ~ 'OTHER'))

#  num    city  city2
#1   1   BORNE BOERNE
#2   2 BOERNAE BOERNE
#3   3   BARNE BOERNE
#4   4  BOERNE BOERNE
#5   5  GALDEN GOLDEN
#6   6  GELDON GOLDEN
#7   7 GOELDEN GOLDEN
#8   8  GOLDEN GOLDEN
0 голосов
/ 20 апреля 2020

У меня есть пакет на github, который может помочь, который позволяет перекодировать уровни факторов с сопоставлением с регулярным выражением. Загрузка с пакетом с

devtools::install_github("jwilliman/xfactor")

citA <- data.frame("num" = c(1,2,3,4,5,6,7,8),
                   "city" = c("BORNE","BOERNAE","BARNE","BOERNE",
                              "GALDEN","GELDON","GOELDEN","GOLDEN"))

citA$city2 <- xfactor::xfactor(citA$city, levels = c(BOERNE = "BOR|BOE|BAR", GOLDEN = "GAL|GEL|GOE|GOL"))

citA
#>   num    city  city2
#> 1   1   BORNE BOERNE
#> 2   2 BOERNAE BOERNE
#> 3   3   BARNE BOERNE
#> 4   4  BOERNE BOERNE
#> 5   5  GALDEN GOLDEN
#> 6   6  GELDON GOLDEN
#> 7   7 GOELDEN GOLDEN
#> 8   8  GOLDEN GOLDEN

Создано в 2020-04-20 с помощью представительного пакета (v0.3.0)

В противном случае вы можете использовать следующую функцию для очистки / обновления уровней факторов, используя аналогичный синтаксис.


  citA <- data.frame("num" = c(1,2,3,4,5,6,7,8),
                     "city" = c("BORNE","BOERNAE","BARNE","BOERNE",
                                "GALDEN","GELDON","GOELDEN","GOLDEN"))

make_levels <- function(.f, patterns, replacement = NULL, ignore.case = FALSE) {

  lvls <- levels(.f)

  # Replacements can be listed in the replacement argument, taken as names in patterns, or the patterns themselves.
  if(is.null(replacement)) {
    if(is.null(names(patterns)))
      replacement <- patterns
    else
      replacement <- names(patterns)
  }

  # Find matching levels
  lvl_match <- setNames(vector("list", length = length(patterns)), replacement)
  for(i in seq_along(patterns))
    lvl_match[[replacement[i]]] <- grep(patterns[i], lvls, ignore.case = ignore.case, value = TRUE)

  # Append other non-matching levels
  lvl_other <- setdiff(lvls, unlist(lvl_match))
  lvl_all <- append(
    lvl_match, 
    setNames(as.list(lvl_other), lvl_other)
  )

  return(lvl_all)

}

levels(citA$city) <- make_levels(citA$city, c(BOERNE = "BOR|BOE|BAR", GOLDEN = "GAL|GEL|GOE|GOL"))

citA
#>   num   city
#> 1   1 BOERNE
#> 2   2 BOERNE
#> 3   3 BOERNE
#> 4   4 BOERNE
#> 5   5 GOLDEN
#> 6   6 GOLDEN
#> 7   7 GOLDEN
#> 8   8 GOLDEN

Создан в 2020-04-20 пакетом представлением ( v0.3.0)

0 голосов
/ 19 апреля 2020

Мы можем paste в одну строку для pattern в grep с | (что означает OR). Аргумент pattern в grep не векторизован, то есть он принимает только один элемент

citA$city[grepl(paste(c("BOR","BOE","BAR"), collapse="|"),citA$city)] <- "BOERNE" 
citA
#  num    city
#1   1  BOERNE
#2   2  BOERNE
#3   3  BOERNE
#4   4  BOERNE
#5   5  GALDEN
#6   6  GELDON
#7   7 GOELDEN
#8   8  GOLDEN

ПРИМЕЧАНИЕ. Столбец 'city' создается как factor. Это должен быть класс character с использованием stringsAsFactors = FALSE

data

citA <- data.frame("num" = c(1,2,3,4,5,6,7,8),
           "city" = c("BORNE","BOERNAE","BARNE","BOERNE",
                      "GALDEN","GELDON","GOELDEN","GOLDEN"),
        stringsAsFactors = FALSE)
...