【问题标题】:Merging two Data Frames using Fuzzy/Approximate String Matching in R在 R 中使用模糊/近似字符串匹配合并两个数据帧
【发布时间】:2011-01-14 23:26:12
【问题描述】:

描述

我有两个数据集,其中包含需要合并的信息。我拥有的唯一常见字段是不完全匹配的字符串和可能大不相同的数字字段

解释问题的唯一方法是向您展示数据。这是a.csvb.csv。我正在尝试将 B 合并到 A。

B 中有 3 个字段,A 中有 4 个字段。公司名称(仅限文件 A)、基金名称、资产类别和资产。到目前为止,我的重点是尝试通过替换单词或部分字符串来匹配基金名称以创建完全匹配,然后使用:

a <- read.table(file = "http://bertelsen.ca/R/a.csv",header=TRUE, sep=",", na.strings=F, strip.white=T, blank.lines.skip=F, stringsAsFactors=T) 
b <- read.table(file = "http://bertelsen.ca/R/b.csv",header=TRUE, sep=",", na.strings=F, strip.white=T, blank.lines.skip=F, stringsAsFactors=T)
merge(a,b, by="Fund.Name") 

但是,这只能使我获得大约 30% 的匹配。其余的我必须手动完成。

资产是一个数字字段,在这两个字段中并不总是正确的,并且如果基金的资产较少,则可能会有很大差异。 Asset Class 是一个字符串字段,在两个文件中“通常”相同,但是存在差异。

更复杂的是不同系列的基金,在文件 B 中。例如:

AGF 加拿大价值

AGF 加拿大价值-D

在这些情况下,我必须选择没有序列化的那个,或者选择一个叫做“A”、“-A”或“Advisor”的作为匹配。

问题

您认为最好的方法是什么?这个练习是我必须每月做的事情,手动匹配它们非常耗时。代码示例将很有帮助。

想法

我认为可能有效的一种方法是根据字符串中每个单词的第一个大写字母对字符串进行规范化。但我一直无法弄清楚如何使用 R 实现这一目标。

我考虑的另一种方法是根据资产、基金名称、资产类别和公司的组合创建匹配索引。但同样,我不确定如何使用 R 来执行此操作。或者,就此而言,是否可能。

非常感谢代码、cmets、想法和方向的示例!

【问题讨论】:

  • 如果我们谈论字符串匹配,那么?agrep(在基本包中)。
  • 如果您可以将数据作为帖子的一部分,这样我们就可以在发布几年后使用该示例。谢谢。
  • 确实是几年后数据不存在了
  • 6 年前。我会查找数据,如果找到,请更新问题。虽然,我认为答案说明了解决方案。

标签: r fuzzy-search


【解决方案1】:

强烈建议使用dgrtwo/fuzzyjoin 包。 stringdist_inner_join(a,b, by="Fund.Name")

【讨论】:

    【解决方案2】:

    一个快速的建议:尝试在使用合并之前分别对不同的字段进行一些匹配。最简单的方法是使用 pmatch 函数,尽管 R 不缺少文本匹配函数(例如 agrep)。这是一个简单的例子:

    pmatch(c("med", "mod"), c("mean", "median", "mode"))
    

    对于您的数据集,这匹配 a 中的所有基金名称:

    > nrow(merge(a,b,x.by="Fund.Name", y.by="Fund.name"))
    [1] 58
    > length(which(!is.na(pmatch(a$Fund.Name, b$Fund.name))))
    [1] 238
    

    创建匹配后,您可以使用它们轻松地将它们合并在一起。

    【讨论】:

    • 谢谢 Shane,您的建议总是很有帮助 - 我会看看这两个,然后告诉您结果如何。
    • 是的,很好的建议 Shane。
    • 当名字更脏时,问题就更多了。说明第一个单词何时可能是缩写形式,也可能不是缩写形式,以及其余单词何时可能是缩写形式,也可能不是。这种缩写在单个名称或跨名称中不一致。
    【解决方案3】:

    近似字符串匹配不是一个好主意,因为不正确的匹配会使整个分析无效。如果每个来源的名称每次都相同,那么构建索引对我来说也是最好的选择。这在 R 中很容易做到:

    假设你有数据:

    a<-data.frame(name=c('Ace','Bayes'),price=c(10,13))
    b<-data.frame(name=c('Ace Co.','Bayes Inc.'),qty=c(9,99))
    

    为每个来源建立一个名称索引,可能使用 pmatch 等作为起点,然后手动验证。

    a.idx<-data.frame(name=c('Ace','Bayes'),idx=c(1,2))
    b.idx<-data.frame(name=c('Ace Co.','Bayes Inc.'), idx=c(1,2))
    

    然后对于每次运行合并使用:

    a.rich<-merge(a,a.idx,by="name")
    b.rich<-merge(b,b.idx,by="name")
    merge(a.rich,b.rich,by="idx")
    

    这会给我们:

      idx name.x price     name.y qty
    1   1    Ace    10    Ace Co.   9
    2   2  Bayes    13 Bayes Inc.  99
    

    【讨论】:

    • 当名字更脏时,问题就更多了。说明第一个单词何时可能是缩写形式,也可能不是缩写形式,以及其余单词何时可能是缩写形式,也可能不是。这种缩写在单个名称或跨名称中不一致。
    【解决方案4】:

    我也是加拿大本地人,请认出基金名称。

    这是一个困难的过程,因为每个数据提供商都会为各个基金名称选择自己的表格。有些使用不同的结构,例如全部以基金或类别结尾,而其他则到处都是。每个人似乎也选择了自己的短格式,并且这些格式会定期更改。

    这就是为什么有这么多人像你一样定期手工完成这项工作。一些咨询公司确实列出了链接各种来源的索引,不确定您是否探索过这条路线?

    正如 Shane 和 Marek 所指出的,这是一项匹配任务,而不是直接连接。许多公司都在为此苦苦挣扎。我正在做这方面的工作......

    【讨论】:

    • 令人沮丧。我真的很惊讶他们没有分配代码。命名完全没有标准化,甚至资产类别在同一年从一个供应商到下一个供应商都不匹配,更不用说同一个月了。如果你正在研究这个,我很想有机会更详细地讨论它:Brandon AT bertelsen dot ca is me.
    • 肯定是,有些人有代码,但他们只是在他们自己的系统中的标识符......我也希望有机会讨论和合作。我很快就会给你发一封电子邮件。
    • 看来我只能对我自己的答案发表评论......所以我同意 jmoy 应该构建一个索引(id)来加入不同的来源。关键是创建这些索引;)一些标准的东西有效,有些则无效。这是一个很难的。有没有经验丰富的数据集成商可能知道我们中的一些人可能不知道的事情?近似匹配和所有环绕是我发现开始解决此类问题的最自动化方式。
    • Jay,我不记得你的电子邮件地址了——但我有办法解决这个问题。我们应该重新连接。
    猜你喜欢
    • 2014-12-30
    • 1970-01-01
    • 2020-07-30
    • 2021-09-10
    • 2017-12-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多