【问题标题】:R - String Distance with weighted wordsR - 带加权词的字符串距离
【发布时间】:2018-11-04 02:06:11
【问题描述】:

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

通常我的字符串共享一个常用词,例如“city”或“university”,结果得到相对接近的字符串距离匹配,但非常不同(即:“University of Utah”和“University of Ohio” ,或“XYZ 城市”和“ABC 城市”)。

我知道操作(删除、插入、替换)的权重可能因算法而异,但我还没有看到一种方法来包含与权重配对的单词列表。有什么想法吗?

当然,一种选择是在匹配之前str_remove 那些常用词,但问题在于“XYZ 县”和“XYZ 市”看起来相同。

例子:

“犹他大学”和“俄亥俄大学”

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

标准化的字符串距离为 0.22222。这是相对较低的。但实际上,“Utah”和“Ohio”之间的归一化 OSA 字符串距离是 1:

4 / 18 = 0.222222

但是,事先删除“University of”和“State”等其他常见字符串会导致“University of Ohio”和“Ohio State”之间匹配。

对诸如“University of”之类的字符串进行加权计算,例如规范化分母中使用的实际字符数的 0.25 将减少这些常见子字符串的影响,即:

4 / (18 * 0.25) = 0.888888。

当我们考虑对州与大学的例子做同样的事情时,这里就变得模糊了:

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

收益率为 16。但取分母的 0.25:

16 / (18 * .25) = 3.55555。

也许更好的选择是使用 LCS,但降低匹配常见字符串列表的子字符串。所以即使“University of Utah”和“University of Ohio”有一个14个字符的公共子串,如果“University of”出现在这个列表中,它的LCS值就会降低。

编辑:另一个想法

我有另一个想法 - 使用 tidytext 包和 unnest_tokens,可以生成所有匹配字符串中最常见单词的列表。考虑相对于它们在数据集中的共性来降低这些词的权重可能会很有趣,因为它们越常见,它们的区分能力就越小......

【问题讨论】:

  • 当您想忽略常用词和/或词的顺序不同时,qgram 距离 (stringdist::stringdist(x,y,method='qgram',q=3)) 通常效果很好。
  • 谢谢马克,我看到由于qgram 计算不常见的 qgram,“俄亥俄大学”和“犹他大学”将占“俄亥俄/犹他州”而不受到影响由“大学”。很有帮助!

标签: r stringdist


【解决方案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" ?

【讨论】:

  • 谢谢!我喜欢这个。基于会产生错误相似性的术语进行分组是一个好主意。我会试一试的。
  • @jzadra 很高兴它有帮助!
  • 这实际上是一个很好的解决方案:D,
猜你喜欢
  • 2017-01-07
  • 1970-01-01
  • 2022-01-19
  • 1970-01-01
  • 2015-05-16
  • 1970-01-01
  • 2012-10-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多