Наилучшее совпадение каждого элемента в строке со многими строками - PullRequest
1 голос
/ 17 марта 2019

Входные данные:

a <- c("coca cola","hot coffee","Running Shoes","Table cloth",
       ”mobile phones under 5000”,”Amazon kindle”)
b <- c("running shoes","plastic cup","pizza","Let’s go to hill","motor van",
       "coffee table","drinking coffee on a rainy day",”Best mobile phones under 10000”,
       ”kindle e-books”,”Coffee Cup”)

Совпадение каждого слова каждого предложения вектора (здесь вектор a) со всеми строками в отдельном векторе (здесь вектор b) слово за словом и получение наилучшего соответствия.

The expected output

Логика: Все предложения вектора «a» должны совпадать со всеми предложениями вектора «b» слово за словом, а процент долженбыть рассчитанным.В предложении вектора «а» может быть только одно наилучшее совпадение.

Пример 1: «Кроссовки» в векторе «а» идеально соответствуют «Кроссовкам» в векторе «b» и percentage_matchсоставляет 100% (так как оба слова совпадают)

Пример 2: наилучшим соответствием «горячего кофе» может быть «пить кофе в дождливый день» или «кофейный столик» или «кофейная чашка» и процент_матчсоставляет 50% (так как только «кофе» во всех случаях соответствует «горячему кофе»).В таком сценарии, где есть более одного претендента с одинаковым максимумом percentage_match, мы выберем лучшее совпадение с наименьшей длиной строки, то есть «журнальный столик» и «кофейная чашка» получат приоритет над «пить кофе в дождливый день»,Даже после этого есть галстук, мы можем выбрать любую вещь (например, «Журнальный столик» или «Кофейная чашка», может быть лучшим выбором для «горячего кофе»).

Код пробовал:

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

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(mx, 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)

Проблема, с которой сталкиваются: Поскольку мои фактические данные очень большие (более 2 миллионов записей должны быть сопоставлены с 1 Mn записью), этот код работает вечно.

1 Ответ

0 голосов
/ 17 марта 2019

Вот один из способов сделать это, используя stringdistmatrix из пакета stringdist. По сути, мы рассчитываем расстояние между строками в a и b. Тогда мы держим наименьшее расстояние. Всегда будет совпадение, даже если расстояние большое число. Одна вещь, которую вы могли бы сделать, это установить минимальное расстояние, иначе NA.

library(stringdist)
m <- stringdistmatrix(tolower(a), tolower(b), method = "qgram")
b[apply(m, 1, which.min)]

#[1] "plastic cup"                    "coffee table"                   "running shoes"                 
#[4] "coffee table"                   "best mobile phones under 10000" "kindle e-books"
...