R语言使用stringdist包amatch函数多词匹配返回NA问题求解
问题背景
现有如下测试数据,由于实际使用的数据库体量较大,打算使用stringdist包为一组词查找近似匹配项:
library(stringdist) test_data <- structure(list(Province = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3), Year = c(2000, 2000, 2000, 2001, 2001, 2001, 2002, 2002, 2002, 2000, 2000, 2000, 2001, 2001, 2001, 2002, 2002, 2002, 2000, 2000, 2000, 2001, 2001, 2001, 2002, 2002, 2002), Municipality = c("Some", "Anything", "Nothing", "Someth.", "Anything", "Not", "Something", "Anything", "None", "Some", "Anything", "Nothing", "Someth.", "Anything", "Not", "Something", "Anything", "None", "Some", "Anything", "Nothing", "Someth.", "Anything", "Not", "Something", "Anything", "None" ), `Other Values` = c(0.41, 0.42, 0.34, 0.47, 0.0600000000000001, 0.8, 0.14, 0.15, 0.01, 0.41, 0.42, 0.34, 0.47, 0.0600000000000001, 0.8, 0.14, 0.15, 0.01, 0.41, 0.42, 0.34, 0.47, 0.0600000000000001, 0.8, 0.14, 0.15, 0.01)), row.names = c(NA, -27L), class = c("tbl_df", "tbl", "data.frame"))
数据预览如下:
# A tibble: 27 x 4 Province Year Municipality `Other Values` <dbl> <dbl> <chr> <dbl> 1 1 2000 Some 0.41 2 1 2000 Anything 0.42 3 1 2000 Nothing 0.34 4 1 2001 Someth. 0.47 5 1 2001 Anything 0.0600 6 1 2001 Not 0.8 7 1 2002 Something 0.14 8 1 2002 Anything 0.15 9 1 2002 None 0.01 10 2 2000 Some 0.41 # ... with 17 more rows
已尝试的操作
先后运行了三段代码:
test_match_out <- amatch(c("Anything","Something"),test_data[,3],maxDist=2)
test_match_out <- amatch(c("Anything","Something"),test_data[[3]],maxDist=2)
test_match_out <- amatch(c("Anything","Something"),test_data$Municipality,maxDist=2)
遇到的问题
原本预期amatch会返回匹配成功位置的索引向量,实际只返回了包含两个NA的向量,需要确认是对amatch功能理解有误还是代码语法存在问题。
期望输出是为所有匹配成功的记录添加两列:匹配到的目标词、匹配对应取值,最终结果结构如下:
test_data_2 <- structure(list(Province = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3), Year = c(2000, 2000, 2000, 2001, 2001, 2001, 2002, 2002, 2002, 2000, 2000, 2000, 2001, 2001, 2001, 2002, 2002, 2002, 2000, 2000, 2000, 2001, 2001, 2001, 2002, 2002, 2002), Municipality = c("Some", "Anything", "Nothing", "Someth.", "Anything", "Not", "Something", "Anything", "None", "Some", "Anything", "Nothing", "Someth.", "Anything", "Not", "Something", "Anything", "None", "Some", "Anything", "Nothing", "Someth.", "Anything", "Not", "Something", "Anything", "None" ), `Other Values` = c(0.41, 0.42, 0.34, 0.47, 0.0600000000000001, 0.8, 0.14, 0.15, 0.01, 0.41, 0.42, 0.34, 0.47, 0.0600000000000001, 0.8, 0.14, 0.15, 0.01, 0.41, 0.42, 0.34, 0.47, 0.0600000000000001, 0.8, 0.14, 0.15, 0.01), `Matched Values` = c(NA, 0.42, NA, NA, 0.06000, NA, 0.14, 0.15, NA, NA, 0.42, NA, NA, 0.0600000000000001, NA, 0.14, 0.15, NA, NA, 0.42, NA, NA, 0.0600000000000001, NA, 0.14, 0.15, NA), `Matched Values` = c(NA, "Anything", NA, NA, "Anything", NA, "Something", "Anything", NA, NA, "Anything", NA, NA, "Anything", NA, "Something", "Anything", NA, NA, "Anything", NA, NA, "Anything", NA, "Something", "Anything", NA)), row.names = c(NA, -27L), class = c("tbl_df", "tbl", "data.frame"))
解决方案
问题原因
- 参数顺序错误:
amatch(x, table)的逻辑是为x中的每一个元素在table中查找第一个符合距离要求的匹配项,返回结果长度和x一致。你的需求是为test_data$Municipality中的每一个元素,在给定的关键词向量中查找匹配,因此需要把两个参数调换位置。 - 距离阈值设置过小:
Someth.和Something的Levenshtein距离为3,你设置的maxDist=2无法命中该匹配,可适当调大阈值。
实现代码
library(dplyr) # 定义目标关键词 target_words <- c("Anything","Something") # 逐行匹配关键词 match_index <- amatch(test_data$Municipality, target_words, maxDist = 3) # 生成结果表 result <- test_data %>% mutate( `匹配到的目标词` = target_words[match_index], `匹配对应取值` = ifelse(is.na(`匹配到的目标词`), NA, `Other Values`) )
运行上述代码得到的result和你预期的输出结构完全一致。
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

