我一直在研究一种基于不完美字符串(例如公司名称)连接两个数据集的方法。在过去,我必须匹配两个非常脏的列表,一个列表有姓名和财务信息,另一个列表有姓名和地址。都没有唯一的ID来匹配!假设已经进行了清洁,并且可能存在打印错误和插入错误。
到目前为止,AGREP是我发现的最接近的工具。我可以使用AGREP包中的levenshtein距离,它测量两个字符串之间的删除、插入和替换的数量。P将返回具有最小距离(最相似)的字符串。
但是,我在将此命令从单个值转换为将其应用于整个 Dataframe 时遇到了麻烦。我已经粗略地使用了一个for循环来重复AGREP函数,但肯定有更简单的方法。
请参阅下面的代码:
a<-data.frame(name=c('Ace Co','Bayes', 'asd', 'Bcy', 'Baes', 'Bays'),price=c(10,13,2,1,15,1))
b<-data.frame(name=c('Ace Co.','Bayes Inc.','asdf'),qty=c(9,99,10))
for (i in 1:6){
a$x[i] = agrep(a$name[i], b$name, value = TRUE, max = list(del = 0.2, ins = 0.3, sub = 0.4))
a$Y[i] = agrep(a$name[i], b$name, value = FALSE, max = list(del = 0.2, ins = 0.3, sub = 0.4))
}
7条答案
按热度按时间crcmnpdw1#
下面是一个使用
fuzzyjoin
包的解决方案。它使用类似于dplyr
的语法和stringdist
作为模糊匹配的可能类型之一。正如suggested by@C8H10N4O2一样,
stringdist
method=“jw”为您的示例创建了最佳匹配。作为
fuzzyjoin
的开发者@dgrtwo的suggested,我使用了一个大的max_dist
,然后使用dplyr::group_by
和dplyr::slice_min
来获得最小距离的最佳匹配。(slice_min
替换旧的top_n
,如果原始顺序很重要,而不是按字母顺序,请使用mutate(rank = row_number(dist)) %>% filter(rank == 1)
)l3zydbqr2#
该解决方案取决于
a
到b
的匹配所需的基数。如果是一对一,你会得到上面三个最接近的匹配。如果是多对一,你会得到六个。一一对应(需要赋值算法):
当我不得不这样做之前,我把它作为一个分配问题的距离矩阵和分配启发式(贪婪分配使用以下)。如果你想要一个“最佳”解决方案,你最好使用
optim
。不熟悉AGREP,但这里的例子使用
stringdist
为您的距离矩阵。生成分配:
我相信有一种更优雅的方法来进行贪婪分配启发式,但上面的方法对我来说很有效。
多对一(非赋值问题):
生成结果:
**编辑:**使用
method="jw"
生成所需结果。参见help("stringdist-package")
bz4sfanl3#
我不确定这对你是否有用,John Andrews,但它为你提供了另一个工具(来自
RecordLinkage
包),可能会有所帮助。8fsztsew4#
模糊匹配
Approximate String Matching近似匹配一个字符串到另一个字符串。例如
banana
和bananas
。Fuzzy Matching是在字符串中找到一个近似模式。例如
bananas in pyjamas
内的banana
。| | R实现| R Implementation |
| --|--|--|
| 基本|比塔普≈莱文施泰因|
b$name <- lapply(b$name, agrep, a$name, value=TRUE); merge(a,b)
|| 先进|
?stringdist::stringdist-metrics
|fuzzyjoin::stringdist_join(a, b, mode='full', by=c('name'), method='lv')
|| 模糊匹配|TRE|
agrep2 <- function(pattern, x) x[which.min(adist(pattern, x, partial=TRUE))]; b$name <- lapply(b$name, agrep2, a$name); merge(a, b)
|自己跑
ecbunoof5#
我在以下情况下使用
lapply
:那么把它写成csv就不那么简单了:
lrpiutwd6#
同意上面的回答“* 不熟悉AGREP,但这里的例子使用stringdist为您的距离矩阵。*”,但从Merging Data Sets Based on Partially Matched Data Elements添加下面的签名函数将更准确,因为LV的计算基于position/addition/deletion
0h4hbjxa7#
下面是我用来获取公司在列表中出现的次数的方法,尽管公司名称不完全匹配,
step.1安装phonics包
step.2在“mylistofcompanynames”中新建一列“soundexcodes”
step.3使用soundex函数返回soundexcodes中公司名称的soundex编码
step.4将公司名称和相应的soundex代码复制到名为“companynames”和“soundexcode”的新文件(2列)中,名为“companynesoundexcodestrainingfile”
step.5删除companysoundexcodestrainingfile中重复的soundexcodes
step.6浏览剩余公司名称的列表,并按照您希望其出现在原始公司中的方式更改名称
step.6通过“soundexcodes”在companysoundexcodestrainingfile$soundexcodes和mystofcompanynames $soundexcodes之间执行left_join或(简单vlookup)
step.7结果应该有原始列表,新列名为“co.y”,其中有公司的名称,就像你在培训文件中留下的那样。
step.8对“co.y”进行排序,并检查大部分公司名称是否匹配正确,如果匹配正确,则将旧公司名称替换为soundex代码的vlookup给出的新公司名称。