Фильтруйте строки на основе наличия строкового элемента из другого столбца

#r #string #stringr #fuzzyjoin

Вопрос:

Я пытаюсь отфильтровать соответствующие строки на основе наличия или существования строки или части/элемента строки в R. Ниже приведен пример:

 colA                                      colb                           flag
New York Metropolitan Area                New York                       Yes 
New York Metropolitan Area                York                           Yes
New York Metropolitan Area                New York Area                  Yes
New York Metropolitan Area                Los Angeles                    No 
 

Вещи, которые я пробовал до сих пор:

  1. Где присутствуют 2 разных фрейма данных
 df1<- df1 %>% fuzzy_inner_join(df2, by = c("colA" = "colB"), match_fun = str_detect)
 

Эта опция не работает из-за парантеза и других специальных символов, очистка их всех также не помогла.

  1. Я соединил 2 фрейма данных на основе иерархии верхнего уровня, чтобы ограничить строки, и создал фрейм данных df
 df[, "lookup"] <- gsub(" ", "|", df[,"colB"])

df[,"flag"] <- mapply(grepl, df[,"lookup"], df[,"colA"])
 

Результаты неудовлетворительны, так как фильтруются только ограниченные строки.

Заранее спасибо.

Комментарии:

1. Вы пишете «Где присутствуют 2 разных кадра данных», но в вопросе есть только один df . Можете ли вы сделать вопрос более ясным?

2. Пожалуйста, рассматривайте только попытку 2 как ту, которую я ищу. Я просто привел множество подходов, которые могут быть применены, и попытка 1 просто описывает это. Спасибо

Ответ №1:

Вот базовое решение R.
Анонимная лямбда-функция (x, y) была введена в R 4.1.0 для использования в более старых версиях function(x, y) R.

 pattern <- gsub(" ", "|", df1$colb)
i <- mapply((x, y)grepl(x, y), pattern, df1$colA)
df1$flag <- c("No", "Yes")[i   1L]

df1
#                        colA          colb flag
#1 New York Metropolitan Area      New York  Yes
#2 New York Metropolitan Area          York  Yes
#3 New York Metropolitan Area New York Area  Yes
#4 New York Metropolitan Area   Los Angeles   No
 

Чтобы удалить строки, не соответствующие шаблонам:

 df1[i, ]
#                        colA          colb flag
#1 New York Metropolitan Area      New York  Yes
#2 New York Metropolitan Area          York  Yes
#3 New York Metropolitan Area New York Area  Yes
 

Данные

 df1 <-
structure(list(colA = c("New York Metropolitan Area", 
"New York Metropolitan Area", "New York Metropolitan Area", 
"New York Metropolitan Area"), colb = c("New York", "York", 
"New York Area", "Los Angeles"), flag = c("Yes", "Yes", "Yes", 
"No")), row.names = c(NA, -4L), class = "data.frame")
 

Комментарии:

1. Извините за поздний ответ. Получаю эту ошибку Error: unexpected input in "i <- mapply(" при запуске i <- mapply((x, y)grepl(x, y), pattern, df1$colA)

2. исправлено и работает. Спасибо. Обновлено R. Спасибо

Ответ №2:

Если я правильно понял ваш вопрос, вы пытаетесь сопоставить частичные строки и получить новый столбец, указывающий на совпадение:

 df1 <- data.frame(colA = rep("New York Metropolitan Area ", 4),
                  colb = c("New York", "York", "New York Area", "Los Angeles") )
 

Моя первая попытка была простой str_detect , но она пытается сопоставить всю строку в colb in colA :

 df3 = df1%>%
  mutate(flag =  str_detect(colA, colb))

> df3
                         colA          colb  flag
1 New York Metropolitan Area       New York  TRUE
2 New York Metropolitan Area           York  TRUE
3 New York Metropolitan Area  New York Area FALSE
4 New York Metropolitan Area    Los Angeles FALSE
 

Это не совсем правильно; хотя в этом примере вы могли бы просто добавить df1$colb = gsub("Area", "", df1$colb ) сначала.

альтернативно:

 library(dplyr) # for pipe
library(stringr) # for str_detect
library(tidyr) # for separate

#separate colb into 3 columns (called b1,b2 and b3) with separate words (can be increased if more words)
df1 = df1 %>% separate(col = colb, c("b1","b2","b3")) 

# detect contents of columns b1, b2 or b3 in colA and create new column with logical value
df2 = df1%>%
    mutate(flag = str_detect(colA, b1)| 
                  str_detect(colA, b2)|
                  str_detect(colA, b3))
 

Это дает результат

 > df2
                         colA   b1      b2   b3 flag
1 New York Metropolitan Area   New    York <NA> TRUE
2 New York Metropolitan Area  York    <NA> <NA> TRUE
3 New York Metropolitan Area   New    York Area TRUE
4 New York Metropolitan Area   Los Angeles <NA>   NA