R - 带加权词

时间:2018-05-24 18:48:38

标签: r stringdist

有没有办法使用stringdist包或其他字符串距离包来加权特定单词?

我经常会有一些共同的词汇,例如" city"或者"大学"因此得到相对接近的弦距匹配,但是非常不同(即:"犹他大学"和#34;俄亥俄大学"或" XYZ City"和#34; ABC City")。

我知道操作(删除,插入,替换)可以根据算法进行不同的加权,但我还没有看到包含与权重配对的单词列表的方法。有什么想法吗?

当然,在匹配之前,一个选项是str_remove这些常用词,但是在那个" XYZ县"和" XYZ City"看起来很相似。

示例:

"犹他大学"和#34;俄亥俄大学"

stringdist("University of Utah", "University of Ohio") / max(nchar("University of Utah"), nchar("University of Ohio"))

标准化的字符串距离为0.22222。这个数字相对较低。但实际上,"犹他州和#34;之间的标准化OSA字符串距离。和"俄亥俄州"是1:

4/18 = 0.222222

然而,删除"大学"和其他常见的字符串,如" State"之前会导致俄亥俄大学和#34;之间的比赛。和"俄亥俄州"。

加权像"大学"计算,比如归一化分母中使用的实际字符数的0.25将减少这些公共子串的影响,即:

4 /(18 * 0.25)= 0.888888。

当我们考虑对State vs University示例做同样的事情时,它会变得模糊:

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

收益率16.但是以0.25的分母:

16 /(18 * .25)= 3.55555。

也许更好的选择是使用LCS但是匹配常见字符串列表的低重子串。所以,尽管"犹他大学"和#34;俄亥俄大学"有一个14个字符的共同子串,如果"大学"出现在这个列表中,它的LCS值会减少。

编辑:另一个想法

我有另一个想法 - 使用tidytext包和unnest_tokens,可以生成所有匹配字符串中最常见单词的列表。考虑将这些词相对于它们在数据集中的共性进行减重可能会很有意思,因为它们越常见,它们的差异性就越小......

1 个答案:

答案 0 :(得分:2)

也许有一个想法可能是在计算字符串距离之前重新组合相似的术语,以避免比较" Ohio State"和#34;俄亥俄大学"共。

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