#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
Вещи, которые я пробовал до сих пор:
- Где присутствуют 2 разных фрейма данных
df1<- df1 %>% fuzzy_inner_join(df2, by = c("colA" = "colB"), match_fun = str_detect)
Эта опция не работает из-за парантеза и других специальных символов, очистка их всех также не помогла.
- Я соединил 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