R - Строка Расстояние с взвешенными словами - PullRequest
0 голосов
/ 24 мая 2018

Можно ли как-нибудь взвесить определенные слова, используя пакет stringdist или другой пакет расстояния между строками?

Часто у меня есть строки, которые имеют общее слово, такое как "город" или "университет", которые получают относительнов результате совпадения расстояний между близкими строками, но очень разные (то есть: "Университет Юты" и "Университет Огайо" или "Город XYZ" и "Город ABC").

Я знаю, что операции (удаление, вставка, замена) могут быть взвешены по-разному в зависимости от алгоритма, но я не видел способа включить список слов в паре с весами.Есть мысли?

Конечно, одним из вариантов было бы 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

Тем не менее, при удалении «Университета» и других распространенных строк, таких как «State»«Перед рукой приведет к матчам между« Университетом Огайо »и« Штатом Огайо ».

Взвешивание строки, такой как «Университет», для подсчета, скажем, 0,25 фактического количества символов, используемых в знаменателе нормализации, уменьшит влияние этих общих подстрок, то есть:

4 /(18 * 0,25) = 0,888888.

Здесь становится неясным, когда мы рассматриваем возможность сделать то же самое с примером штата против университета:

stringdist("University of Ohio", "Ohio State")

дает 16. Но взяв 0,25 знаменателя:

16 / (18 * .25) = 3.55555.

Возможно, лучшим вариантом было бы использовать LCS, но подстроки с меньшим весом, которые соответствуют списку общих строк.Поэтому, несмотря на то, что «Университет Юты» и «Университет Огайо» имеют общую подстроку из 14 символов, если «Университет» появится в этом списке, значение LCS для него будет уменьшено.

Редактировать: Другая мысль

У меня была другая мысль - используя пакет tidytext и unnest_tokens, можно генерировать список наиболее распространенных слов во всех сопоставляемых строках.Возможно, было бы интересно рассмотреть занижение этих слов относительно их общности в наборе данных, поскольку чем они более распространены, тем меньше у них различающей способности ...

1 Ответ

0 голосов
/ 26 мая 2018

Может быть, одна идея может заключаться в том, чтобы перегруппировать подобные термины перед вычислением расстояния между строками, чтобы избежать полного сравнения "штата Огайо" и "университета Огайо".

# 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" ?
...