如何准匹配两个字符串向量(在R中)?


36

我不确定该如何称呼,所以如果您知道一个更好的术语,请更正我。

我有两个清单。55个项目之一(例如:字符串向量),另一个为92。项目名称相似但不相同。

我希望能够找到的最佳人选小号在92名单于55列表中的项目(然后我会去通过它,并选择正确的装修)。

怎么做到呢?

我有以下想法:

  1. 查看所有匹配项(使用某项列表?match)
  2. 尝试在字符串向量之间使用距离矩阵,但是我不确定如何最好地定义它(相同字母的数量,字符串的顺序如何?)

那么,什么软件包/功能/研究领域可以处理此类任务呢?

更新:这是我要匹配的向量的示例

vec55 <- c("Aeropyrum pernix", "Archaeoglobus fulgidus", "Candidatus_Korarchaeum_cryptofilum", 
"Candidatus_Methanoregula_boonei_6A8", "Cenarchaeum_symbiosum", 
"Desulfurococcus_kamchatkensis", "Ferroplasma acidarmanus", "Haloarcula_marismortui_ATCC_43049", 
"Halobacterium sp.", "Halobacterium_salinarum_R1", "Haloferax volcanii", 
"Haloquadratum_walsbyi", "Hyperthermus_butylicus", "Ignicoccus_hospitalis_KIN4", 
"Metallosphaera_sedula_DSM_5348", "Methanobacterium thermautotrophicus", 
"Methanobrevibacter_smithii_ATCC_35061", "Methanococcoides_burtonii_DSM_6242"
)
vec91 <- c("Acidilobus saccharovorans 345-15", "Aciduliprofundum boonei T469", 
"Aeropyrum pernix K1", "Archaeoglobus fulgidus DSM 4304", "Archaeoglobus profundus DSM 5631", 
"Caldivirga maquilingensis IC-167", "Candidatus Korarchaeum cryptofilum OPF8", 
"Candidatus Methanoregula boonei 6A8", "Cenarchaeum symbiosum A", 
"Desulfurococcus kamchatkensis 1221n", "Ferroglobus placidus DSM 10642", 
"Halalkalicoccus jeotgali B3", "Haloarcula marismortui ATCC 43049", 
"Halobacterium salinarum R1", "Halobacterium sp. NRC-1", "Haloferax volcanii DS2", 
"Halomicrobium mukohataei DSM 12286", "Haloquadratum walsbyi DSM 16790", 
"Halorhabdus utahensis DSM 12940", "Halorubrum lacusprofundi ATCC 49239", 
"Haloterrigena turkmenica DSM 5511", "Hyperthermus butylicus DSM 5456", 
"Ignicoccus hospitalis KIN4/I", "Ignisphaera aggregans DSM 17230", 
"Metallosphaera sedula DSM 5348", "Methanobrevibacter ruminantium M1", 
"Methanobrevibacter smithii ATCC 35061", "Methanocaldococcus fervens AG86", 
"Methanocaldococcus infernus ME", "Methanocaldococcus jannaschii DSM 2661", 
"Methanocaldococcus sp. FS406-22", "Methanocaldococcus vulcanius M7", 
"Methanocella paludicola SANAE", "Methanococcoides burtonii DSM 6242", 
"Methanococcus aeolicus Nankai-3", "Methanococcus maripaludis C5", 
"Methanococcus maripaludis C6", "Methanococcus maripaludis C7", 
"Methanococcus maripaludis S2", "Methanococcus vannielii SB", 
"Methanococcus voltae A3", "Methanocorpusculum labreanum Z", 
"Methanoculleus marisnigri JR1", "Methanohalobium evestigatum Z-7303", 
"Methanohalophilus mahii DSM 5219", "Methanoplanus petrolearius DSM 11571", 
"Methanopyrus kandleri AV19", "Methanosaeta thermophila PT", 
"Methanosarcina acetivorans C2A", "Methanosarcina barkeri str. Fusaro", 
"Methanosarcina mazei Go1", "Methanosphaera stadtmanae DSM 3091", 
"Methanosphaerula palustris E1-9c", "Methanospirillum hungatei JF-1", 
"Methanothermobacter marburgensis str. Marburg", "Methanothermobacter thermautotrophicus str. Delta H", 
"Nanoarchaeum equitans Kin4-M", "Natrialba magadii ATCC 43099", 
"Natronomonas pharaonis DSM 2160", "Nitrosopumilus maritimus SCM1", 
"Picrophilus torridus DSM 9790", "Pyrobaculum aerophilum str. IM2", 
"Pyrobaculum arsenaticum DSM 13514", "Pyrobaculum calidifontis JCM 11548", 
"Pyrobaculum islandicum DSM 4184", "Pyrococcus abyssi GE5", "Pyrococcus furiosus DSM 3638", 
"Pyrococcus horikoshii OT3", "Staphylothermus hellenicus DSM 12710", 
"Staphylothermus marinus F1", "Sulfolobus acidocaldarius DSM 639", 
"Sulfolobus islandicus L.D.8.5", "Sulfolobus islandicus L.S.2.15", 
"Sulfolobus islandicus M.14.25", "Sulfolobus islandicus M.16.27", 
"Sulfolobus islandicus M.16.4", "Sulfolobus islandicus Y.G.57.14", 
"Sulfolobus islandicus Y.N.15.51", "Sulfolobus solfataricus P2", 
"Sulfolobus tokodaii str. 7", "Thermococcus gammatolerans EJ3", 
"Thermococcus kodakarensis KOD1", "Thermococcus onnurineus NA1", 
"Thermococcus sibiricus MM 739", "Thermofilum pendens Hrk 5", 
"Thermoplasma acidophilum DSM 1728", "Thermoplasma volcanium GSS1", 
"Thermoproteus neutrophilus V24Sta", "Thermosphaera aggregans DSM 11486", 
"Vulcanisaeta distributa DSM 14429", "uncultured methanogenic archaeon RC-I"
) 

2
嗨,塔尔(Tal):>鉴于这些似乎不是拼写错误的科学名称,我将首先尝试Levenshtein度量标准(在92 x 55距离矩阵的背景下),然后看看它是如何得出的。
user603 2010年

2
一段时间后,该stringdist软件包似乎是此类事情的最佳资源。
shabbychef

Answers:


18

我也遇到过类似的问题。(在这里看到:https//stackoverflow.com/questions/2231993/merging-two-data-frames-using-fuzzy-approximate-string-matching-in-r

我收到的大多数建议都是:

pmatch()agrep()grep()grepl()三种功能,如果你花时间翻阅将为您提供一些见解近似串匹配或者通过近似串或近似正则表达式。

没有看到字符串,很难为您提供如何匹配字符串的示例。如果您可以为我们提供一些示例数据,我相信我们可以找到解决方案。

我发现效果不错的另一个选择是将字符串展平tolower(),查看字符串中每个单词的第一个字母,然后进行比较。有时,这种方法毫无问题。然后还有更复杂的事情,例如其他答案中提到的距离。有时这些工作有效,有时又很可怕-这实际上取决于字符串。

我们可以看到他们吗?

更新资料

看起来agrep()可以解决大多数问题。注意agrep()只是R的Levenshtein距离的实现。

agrep(vec55[1],vec91,value=T)

尽管有些人没有计算,但我什至不确定酸铁质铁质是否与费罗酸铁质DSM 10642相同,例如:

agrep(vec55[7],vec91,value=T) 

我认为您可能对其中的某些人有些了解,也许从头开始创建索引是最好的选择。即。为vec55创建一个具有ID号的表,然后在vec91中的vec55中手动创建对该ID的引用。我知道很痛苦,但是很多事情可以使用agrep()完成。


嗨,布兰登-我添加了数据样本。谢谢!
Tal Galili 2010年

嗨,布兰登-您的解决方案效果很好-谢谢。
Tal Galili 2010年

+1指向SE中关于该主题的上一个问题的链接(表示指向agrep()的指针)。
user603 2010年

15

有很多方法可以测量两个琴弦之间的距离。R中广泛使用的两个重要(标准)方法是Levenshtein和汉明距离。前者在“ MiscPsycho”软件包中可用,而后者在“ e1071”软件包中可用。使用这些,我将简单地计算成对距离的92 x 55矩阵,然后从那里开始(即,列表1中字符串“ 1”的最佳候选匹配是列表2中距离字符串“ 1”最小的字符串“ x”) ”)。

另外,在RecordLinkage包中有一个功能compare()似乎旨在满足您的要求,并使用了所谓的Jaro-Winkler 距离,该距离似乎更适合手头的任务,但是我对此没有经验。

编辑:我正在编辑我的答案,以包括布兰登的注释以及塔尔的代码,以找到与vec55的第一项“ Aeropyrum pernix”的匹配项:

agrep(vec55[1],vec91,ignore.case=T,value=T,max.distance = 0.1, useBytes = FALSE)
[1] "Aeropyrum pernix K1"

8
+1。此外,如果是有帮助的,术语谷歌比较字符串时是“编辑距离”:en.wikipedia.org/wiki/Edit_distance
ARS

@ars:>谢谢,这是一个方便的列表,可用于R搜索引擎并查看结果!
user603 2010年

2
Levenshtein编辑距离是通过agrep()作为基本软件包的一部分实现的
布兰登·

不错的答案Kwak-以后我会看看它!
Tal Galili

就个人而言,我认为这是对塔尔问题的更完整答案。+1指向我们的RecordLinkage-我一定要尝试一下。
布兰登·贝特尔森

7

为了补充夸克的有用答案,请允许我添加一些简单的原理和想法。确定指标的一种好方法是考虑字符串可能与目标之间的差异。当变化是印刷错误的组合,例如换位邻居或错误键入单个键时,“编辑距离”很有用。

另一种有用的方法(原理略有不同)是将每个字符串映射到一类相关字符串的代表中。“ Soundex ”方法可以做到这一点:一个单词的Soundex代码是四个字符的序列,这些字符编码主辅音和听起来相似的内部结果组。当单词是拼音错误或彼此变体时使用。在示例应用程序中,您将获取所有目标词,它们的Soundex代码等于每个探测词的Soundex代码。(以这种方式可以获取零个或多个目标。)


3

我还建议您除了Kwak的其他建议外,还要检查一下N-gramDamerau–Levenshtein距离。

在这里提到的几个不同的编辑距离的准确度进行比较(并大量引用根据Google学术搜索)。

如您所见,有许多不同的方法可以解决此问题,甚至可以合并不同的指标(我链接到的论文讨论了这一点)。我认为Levenshtein和相关的基于指标的方法最直观,特别是如果由于人工输入而发生错误时。N-gram也很简单,对于不是说名字或单词的数据有意义。

虽然可以选择soundex,但我见过的一小部分工作(虽然数量很少),但与匹配名称的Levenshstein或其他编辑距离相比,soundex的表现不佳。Soundex仅限于人类打字员可能输入的语音短语,因为Levenshtein和N-gram的范围可能更广(尤其是N-gram,但我希望Levenshtein距离对非单词也有更好的表现)。

关于包,我无能为力,但是N-gram的概念非常简单(我最近做了一个SPSS宏来执行N-gram,但是对于这样一个小项目,我将使用已经制作好的包中的N-gram。 R其他海报已建议)。是在python中计算Levenshtein距离的示例。


谢谢安迪-以后我会看看。
Tal Galili 2010年

1

我研究了一些软件包以及解决该问题的方法,我认为最好的选择是fuzzywuzzyR软件包。

FuzzywuzzyR软件包是Fuzzywuzzy python软件包的模糊字符串匹配实现。它使用Levenshtein距离来计算序列之间的差异。有关FuzzywuzzyR功能的更多详细信息,请参见博客文章和Vignette软件包。

我为您的问题做了简单的解决方案,但有一点问题。您必须安装python,如果使用winodows,还必须安装一些用于Visual Studio的构建工具。您必须选择这些:

  • Windows 10 SDK 10.0.17763.0和MSVC v140
  • VS 2015 C ++生成工具(v 14v00)

解决方案很简单。主函数ExtractOne返回两个值的列表。第一个是一个字符串匹配项,第二个是相应的分数(范围为0-100)。该fuzzywuzzyR软件包还提供了其他有用的功能。主要文档可在此处找到。我希望这段代码有助于解决问题。

library(fuzzywuzzyR)

# The Fuzzy initialization
init_proc = FuzzUtils$new()
PROC = init_proc$Full_process # class process-method
PROC1 = tolower # base R function
init_scor = FuzzMatcher$new()
SCOR = init_scor$WRATIO    
init <- FuzzExtract$new()

match_strings <- function(vector_to_process, base_vector){  
  new_vec = c()
  for(i in 1:length(vector_to_process)){      
    new_word <- init$ExtractOne(string = vector_to_process[i], sequence_strings = base_vector, processor = PROC1, scorer = SCOR, score_cutoff = 0L)
    new_vec[i] <- new_word[[1]]
  }     
  return(new_vec)
}

# Check if all python modules are available
if (check_availability()){    
  new_vec <- match_strings(vec55, vec91)
  print(new_vec)   
}

输出:

[1] "Aeropyrum pernix K1"                                 "Archaeoglobus fulgidus DSM 4304"                    
[3] "Candidatus Korarchaeum cryptofilum OPF8"             "Candidatus Methanoregula boonei 6A8"                
[5] "Cenarchaeum symbiosum A"                             "Desulfurococcus kamchatkensis 1221n"                
[7] "Thermoplasma volcanium GSS1"                         "Haloarcula marismortui ATCC 43049"                  
[9] "Halobacterium sp. NRC-1"                             "Halobacterium salinarum R1"                         
[11] "Haloferax volcanii DS2"                              "Haloquadratum walsbyi DSM 16790"                    
[13] "Hyperthermus butylicus DSM 5456"                     "Ignicoccus hospitalis KIN4/I"                       
[15] "Metallosphaera sedula DSM 5348"                      "Methanothermobacter thermautotrophicus str. Delta H"
[17] "Methanobrevibacter smithii ATCC 35061"               "Methanococcoides burtonii DSM 6242"       

0

基于功能 adist

计算字符向量之间的近似字符串距离。该距离是广义的Levenshtein(编辑)距离,给出了将一个字符串转换为另一个字符串所需的最小可能加权的插入,删除和替换次数

stringdist具有相同名称的包中的函数有几种方法(请参阅参考资料?stringdist):

方法= c(“ osa”,“ lv”,“ dl”,“ hamming”,“ lcs”,“ qgram”,“ cosine”,“ jaccard”,“ jw”,“ soundex”)

这样,您可以选择最大散度(阈值):

firstvector<-vec55
secondvector<-vec91

match<-character()
threshold<-14 # max 14 characters of divergence
mindist<-integer()
sortedmatches<-character()

for (i in 1:length(firstvector) ) {
  matchdist<-adist(firstvector[i],secondvector)[1,]
  # matchdist<-stringdist(firstvector[i],secondvector) # several methods available

  matchdist<-ifelse(matchdist>threshold,NA,matchdist)
  sortedmatches[i]<-paste(secondvector[order(matchdist, na.last=NA)], collapse = ", ")
  mindist[i]<- tryCatch(ifelse(is.integer(which.min(matchdist)),matchdist[which.min(matchdist)],NA), error = function(e){NA})
  match[i]<-ifelse(length(secondvector[which.min(matchdist)])==0,NA,
                  secondvector[which.min(matchdist)] )
}
res<-data.frame(firstvector=firstvector,match=match,divergence=mindist, sortedmatches=sortedmatches, stringsAsFactors = F)
res

此数据帧显示列firstvector中的第一个向量,列匹配中的第二个向量的最佳匹配,列分歧中的第二个距离以及按OP中列排序的匹配排序的所有有效匹配。


2
尽管实现通常与问题中的实质内容混合在一起,但我们应该是一个提供有关统计信息,机器学习等信息的网站,而不是代码。也可以提供代码,但是对于那些不太了解该语言以识别并从代码中提取答案的人,请在文本中详细说明您的实质性答案。
gung-恢复莫妮卡
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.