Сопоставление строки без использования цикла

#r #string #pattern-matching

#r #строка #сопоставление с шаблоном

Вопрос:

У меня есть 2 набора данных.

 a <- c("adidas shoes","hot tea","pizza","hill station")
b <- c("shoes","plastic cup","pizza","I love to go to hill","travelling in motor van",
       "buy adidas shoes","run using adidas shoes")
  

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

Для этого я использовал приведенный ниже код:

 a_split <- unlist(strsplit(a[1,], " "))
b_split <- unlist(strsplit(b[1,], " "))
a$match_perc[1] <- length(intersect(a_split, b_split))/length(a_split)*100
  

итак, по сути, то, что я пытаюсь здесь сделать, это сопоставить ‘adidas’ и ‘shoes’ [1-й элемент вектора ‘a’] со всеми элементами вектора ‘b’ и, наконец, получить наилучший процент совпадения и повторить это для всех элементов ‘a’. В случае, если процентное соотношение получается одинаковым, мы всегда будем брать самый высокий процент. По сути, для каждого предложения у меня будет только одно совпадающее предложение в виде одного процента совпадения. В случае, если у нас одинаковый самый высокий процент, мы возьмем 1-е совпадение.

Ожидаемый результат ниже:

 a <- c("adidas shoes","hot tea","pizza","hill station")
Matching_String <- c("buy adidas shoes","NA","pizza","I love to go to hill")
match_perc <- c(100,0,100,50)
final_op <- data.frame(a,Matching_String,match_perc)
  

Ответ №1:

Вы также можете использовать purrr::map функции:

 library(purrr)
match_perc <- map2_dbl(a, Matching_String, function(a, b) {
  a_split <- unlist(strsplit(a, " "))
  b_split <- unlist(strsplit(b, " "))
  length(intersect(a_split, b_split))/length(a_split)*100
})
final_op <- data.frame(a,Matching_String,match_perc)
final_op
             a      Matching_String match_perc
1 adidas shoes     buy adidas shoes        100
2      hot tea                   NA          0
3        pizza                pizza        100
4 hill station I love to go to hill         50
  

Также посмотрите на stringr::str_extract_all функцию для такого извлечения строки

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

1. Вы предположили, что Matching_String это уже существует, что, вероятно, не так. Я признаю, что это несколько сбивает с толку.

2. Когда я пытаюсь использовать ‘map2_dbl’, он показывает мне ошибку Error: .x (579) и .y (4) имеют разную длину

Ответ №2:

Полезен вывод strsplit в виде списков.

 as <- strsplit(a, " ")
bs <- strsplit(b, " ")
  

Вы могли бы создать соответствующую матрицу из этих списков путем векторизации вашей функции и использования outer .

 matchFun <- function(x, y) length(intersect(x, y)) / length(x) * 100
mx <- outer(as, bs, Vectorize(matchFun))
  

Затем поместите максимумы в векторы.

 m <- apply(mx, 1, which.max)  # the maximum column of each row

z <- unlist(apply(p, 1, function(x) x[which.max(x)]))  # maximum percentage
z[z == 0] <- NA  # this gives you the NA if you want it
  

Наконец, поместите результат во фрейм данных.

 data.frame(a, Matching_String=b[m], match_perc=z)

#              a      Matching_String match_perc
# 1 adidas shoes     buy adidas shoes        100
# 2      hot tea                shoes         NA
# 3        pizza                pizza        100
# 4 hill station I love to go to hill         50
  

Данные

 a <- c("adidas shoes","hot tea","pizza","hill station")
b <- c("shoes","plastic cup","pizza","I love to go to hill","travelling in motor van",
       "buy adidas shoes","run using adidas shoes")
  

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

1. Поскольку мой набор данных довольно длинный, ‘внешняя’ функция выполняется вечно. Также, что такое ‘m’ в Matching_String=b[m] ? Когда я пытаюсь использовать ‘map2_dbl’, он показывает мне ошибку Error: .x (579) и .y (4) имеют разную длину

2. О, я забыл вставить строку кода для m , теперь исправлено. Я дал вам решение для предоставленных вами данных. Если это не работает для ваших исходных данных, вам следует привести пример получше, поскольку я с трудом могу их угадать. И в моем коде этого нет map2_dbl ?