R - Строка Расстояние с взвешенными словами
Есть ли способ взвешивания конкретных слов, используя stringdist
пакет или другой пакет расстояния строки?
Часто у меня есть строки, которые имеют общее слово, такое как "город" или "университет", в результате чего получаются относительно близкие совпадения расстояний между строками, но они очень разные (то есть: "Университет Юты" и "Университет Огайо", или "XYZ City"и"ABC City").
Я знаю, что операции (удаление, вставка, замена) могут взвешиваться по-разному в зависимости от алгоритма, но я не видел способа включить список слов в паре с весами. Какие-нибудь мысли?
Конечно, один из вариантов будет str_remove
эти общие слова до сопоставления, но у них есть проблема в том, что "XYZ County" и "XYZ City" будут выглядеть одинаково.
Пример:
"Университет Юты" и "Университет Огайо"
stringdist("University of Utah", "University of Ohio") / max(nchar("University of Utah"), nchar("University of Ohio"))
Нормализованное расстояние до строки составляет 0,22222. Это относительно низко. Но на самом деле нормализованное расстояние между строками OSA между "Ютой" и "Огайо" составляет 1:
4/18 = 0,222222
Однако удаление "University of" и других распространенных строк, таких как "State", может привести к совпадению между "University of Ohio" и "State of Ohio".
Взвешивание строки, такой как "Университет", для подсчета, скажем, 0,25 фактического количества символов, используемых в знаменателе нормализации, уменьшит влияние этих общих подстрок, то есть:
4 / (18 * 0,25) = 0,888888.
Здесь становится нечетко, когда мы рассматриваем возможность сделать то же самое с примером государства против университета:
stringdist("University of Ohio", "Ohio State")
дает 16. Но принимая.25 знаменателя:
16 / (18 *.25) = 3,55555.
Возможно, лучшим вариантом было бы использовать LCS, но подстроки с низким весом, которые соответствуют списку общих строк. Таким образом, несмотря на то, что "Университет Юты" и "Университет Огайо" имеют общую подстроку из 14 символов, если "Университет" появится в этом списке, значение LCS для него будет уменьшено.
Изменить: еще одна мысль
У меня была другая мысль - используя tidytext
пакет и unnest_tokens
можно создать список наиболее распространенных слов во всех сопоставляемых строках. Возможно, было бы интересно рассмотреть вопрос об уменьшении веса этих слов относительно их общности в наборе данных, поскольку чем они чаще встречаются, тем меньше у них дифференцирующей силы...
1 ответ
Возможно, одна идея может заключаться в том, чтобы перегруппировать похожие термины перед вычислением расстояния между строками, чтобы вообще не сравнивать штат Огайо и Университет Огайо.
# Strings
v1 <- c("University of Ohio", "University of Utah", "Ohio State", "Utah State",
"University Of North Alabama", "University of South Alabama", "Alabama State",
"Arizona State University Polytechnic", "Arizona State University Tempe",
"Arizona State", "Metropolitan State University of Denver",
"Metropolitan University Of The State Of Denver", "University Of Colorado",
"Western State Colorado University", "The Dalton College", "The Colorado State",
"The Dalton State College", "Columbus State University", "Dalton College")
# Remove stop words
v2 <- strsplit(v1, " ") %>%
map_chr(~ paste(.x[!tolower(.x) %in% tm::stopwords()], collapse = " "))
# Define groups
groups <- c(Group1 = "state",
Group2 = "university",
Group3 = "college",
# Groups 4-5 must contain BOTH terms
Group4 = ".*(state.*university|university.*state).*",
Group5 = ".*(state.*college|college.*state).*")
# Iterate over the list and assign groups
dat <- list(words = v2, pattern = groups)
lst <- dat$pattern %>% map(~ grepl(.x, dat$words, ignore.case = TRUE))
lst %>%
# Make sure groups 1 to 3 and 4-5 are mutually exclusive
# i.e: if a string contains "state" AND "university" (Group4), it must not be in Group1
modify_at(c("Group1", "Group2", "Group3"),
~ ifelse(lst$Group4 & .x | lst$Group5 & .x, !.x, .x)) %>%
# Return matches from strings
map(~ v2[.x]) %>%
# Compute the stringdistance for each group
map(~ stringdistmatrix(.x, .x)) ## Maybe using method = "jw" ?