【问题标题】:RecordLinkage: how to pair only best matches and export a merged table?RecordLinkage:如何仅配对最佳匹配并导出合并表?
【发布时间】:2016-11-02 13:13:47
【问题描述】:

我正在尝试使用 R 包 RecordLinkage 将采购订单列表中的项目与主目录中的条目进行匹配。下面是 R 代码和使用两个虚拟数据集(DOders 和 Dcatalogue)的可重现示例:

DOrders <- structure(list(Product = structure(c(1L, 2L, 7L, 3L, 4L, 5L, 
6L), .Label = c("31471 - SOFTSILK 2.0 SCREW 7mm x 20mm", "Copier paper white A4 80gsm", 
"High resilience memory foam standard  mattress", "Liston forceps bone cutting 152mm", 
"Micro reciprocating blade 25.4mm x 8.0mm x 0.38mm", "Micro reciprocating blade 39.5 x 7.0 x 0.38", 
"microaire dual tooth 18 x 90 x 0.89"), class = "factor"), Supplier = structure(c(5L, 
6L, 2L, 1L, 4L, 3L, 3L), .Label = c("KAROMED LTD", "Morgan Steer Ortho Limited", 
"ORTHOPAEDIC SOLUTIONS", "SURGICAL HOLDINGS", "T J SMITH NEPHEW LTD", 
"XEROX SOLUTIONS"), class = "factor"), UOI = structure(c(1L, 
1L, 1L, 1L, 1L, 1L, 2L), .Label = c("Each", "Pack"), class = "factor"), 
    Price = c(5.99, 6.99, 40, 230, 35, 80, 79)), .Names = c("Product", 
"Supplier", "UOI", "Price"), class = "data.frame", row.names = c(NA, 
-7L))

DCatalogue <- structure(list(Product = structure(c(7L, 3L, 4L, 5L, 6L, 2L, 
8L, 1L), .Label = c("7.0mm cann canc scr 32x80mm non sterile single use", 
"A4 80gsm white copier paper", "High resilience memory foam standard hospital mattress with stitched seams has a fully enclosing cover", 
"Liston bone cutting forceps with fluted handle straight 152mm", 
"Micro reciprocating blade 25.4mm x 8.0mm x 0.38mm", "Micro reciprocating blade 39.5mm x 7.0mm x 0.38mm", 
"microaire large osc dual tooth 18mm x 90mm x 0.89mm", "Softsilk 2.0 pkg 7x20 ster"
), class = "factor"), Supplier = structure(c(3L, 2L, 6L, 4L, 
4L, 7L, 5L, 1L), .Label = c("BIOMET MERCK LTD", "KAROMED LIMITED", 
"MORGAN STEER ORTHOPAEDICS LTD", "ORTHO SOLUTIONS", "SMITH & NEPHEW ADVANCED SURGICAL DEVICES", 
"SURGICAL HOLDINGS", "XEROX"), class = "factor"), UOI = structure(c(1L, 
1L, 1L, 2L, 2L, 1L, 1L, 1L), .Label = c("Each", "Pack"), class = "factor"), 
    RefPrice = c(38.7, 274.18, 34.96, 79.48, 81.29, 6.99, 5.99, 
    5)), .Names = c("Product", "Supplier", "UOI", "RefPrice"), class = "data.frame", row.names = c(NA, 
-8L))

出于实验目的,DOrders 有 7 个条目,每个条目都与参考集 Dcatalogue 中的九行之一匹配。在真实数据中,并非所有订单都会匹配。

head(DOrders)
                                            Product                   Supplier  UOI  Price
1             31471 - SOFTSILK 2.0 SCREW 7mm x 20mm       T J SMITH NEPHEW LTD Each   5.99
2                       Copier paper white A4 80gsm            XEROX SOLUTIONS Each   6.99
3               microaire dual tooth 18 x 90 x 0.89 Morgan Steer Ortho Limited Each  40.00
4    High resilience memory foam standard  mattress                KAROMED LTD Each 230.00
5                 Liston forceps bone cutting 152mm          SURGICAL HOLDINGS Each  35.00
6 Micro reciprocating blade 25.4mm x 8.0mm x 0.38mm      ORTHOPAEDIC SOLUTIONS Each  80.00

> head(DCatalogue)
                                                                                                 Product                      Supplier  UOI RefPrice
1                                                    microaire large osc dual tooth 18mm x 90mm x 0.89mm MORGAN STEER ORTHOPAEDICS LTD Each    38.70
2 High resilience memory foam standard hospital mattress with stitched seams has a fully enclosing cover               KAROMED LIMITED Each   274.18
3                                          Liston bone cutting forceps with fluted handle straight 152mm             SURGICAL HOLDINGS Each    34.96
4                                                      Micro reciprocating blade 25.4mm x 8.0mm x 0.38mm               ORTHO SOLUTIONS Pack    79.48
5                                                      Micro reciprocating blade 39.5mm x 7.0mm x 0.38mm               ORTHO SOLUTIONS Pack    81.29
6                                                                            A4 80gsm white copier paper                         XEROX Each     6.99

链接的第一步是确保项目按发行单位 (UOI) 匹配。这是因为一包物品显然与一个单位不一样,即使物品完全相同。例如:

Micro reciprocating blade 25.4mm x 8.0mm x 0.38mm      ORTHOPAEDIC SOLUTIONS Each  80.00

是同一个项目,但应该不匹配:

Micro reciprocating blade 25.4mm x 8.0mm x 0.38mm               ORTHO SOLUTIONS Pack    79.48

因此,我使用阻塞参数blockfld = 3 来尝试仅匹配第三列中具有相同值的那些条目。此外,使用 exclude = 4 将价格排除在匹配之外。这将在 Orders 和 Catalog 之间有所不同,这本身就是匹配的主要兴趣所在。匹配是在产品和供应商名称上使用jarowinkler 字符串比较器(如here 所述)完成的:

library(RecordLinkage)

rpairs <- compare.linkage(DOrders, DCatalogue, 
                          blockfld = 3,
                          exclude = 4,
                          strcmp = 1:2,
                          strcmpfun = jarowinkler)

接下来,我正在使用 Contiero 等人计算每对的权重。 (2005)方法:

rpairs <- epiWeights(rpairs)
> summary(rpairs)
Weight distribution:

[0.3,0.4] (0.4,0.5] (0.5,0.6] (0.6,0.7] (0.7,0.8] (0.8,0.9]   (0.9,1] 
        1         1        19        10         3         0         4

根据这个分布,我想将那些权重 > 0.7 的对分类为匹配

result <- epiClassify(rpairs, 0.7)
> summary(result)
7 links detected 
0 possible links detected 
31 non-links detected 

据我所知,这有一些问题。

首先,getPairs(result) 表明来自 DOders 的一个条目可以与 Dcatalogue 中的多个条目具有高权重匹配。例如

这对匹配正确,权重为0.948

Micro reciprocating blade 39.5 x 7.0 x 0.38 ORTHOPAEDIC SOLUTIONS   Pack    79  
Micro reciprocating blade 39.5mm x 7.0mm x 0.38mm   ORTHO SOLUTIONS Pack    81.29   0.9480503

但也与权重 0.928 匹配不正确:

Micro reciprocating blade 39.5 x 7.0 x 0.38 ORTHOPAEDIC SOLUTIONS   Pack    79  
Micro reciprocating blade 25.4mm x 8.0mm x 0.38mm   ORTHO SOLUTIONS Pack    79.48   0.9283522

显然,我需要将配对限制为只有一个权重最高的最佳匹配,但该怎么做呢?

最后,我正在寻找的最终结果是一个合并的数据集,该数据集在一行中包含来自 Orders 和 Catalog 的匹配条目,两个原始集合中的所有列并排进行比较。 getPairs 以一种尴尬的格式生成输出:

> getPairs(result)
    id  Product Supplier    UOI Price   Weight
1   7   Micro reciprocating blade 39.5 x 7.0 x 0.38 ORTHOPAEDIC SOLUTIONS   Pack    79  
2   5   Micro reciprocating blade 39.5mm x 7.0mm x 0.38mm   ORTHO SOLUTIONS Pack    81.29   0.9480503
3                       
4   5   Liston forceps bone cutting 152mm   SURGICAL HOLDINGS   Each    35  
5   3   Liston bone cutting forceps with fluted handle straight 152mm   SURGICAL HOLDINGS   Each    34.96   0.9329244
...

【问题讨论】:

    标签: r duplicates linkage fuzzy-comparison data-linking


    【解决方案1】:

    首先,感谢您提供可重现的示例,这大大简化了您的问题的回答。我将从你的第二个问题开始:

    最后,我正在寻找的最终结果是一个合并的数据集,其中包含一行中来自 Orders 和 Catalog 的匹配条目,两个原始集合中的所有列并排进行比较。

    使用single.rows=TRUE,getPairs 在一行中列出两个条目。此外,show="links" 将输出限制为归类为一起的对(有关详细信息,请参阅?getPairs):

    > matchedPairs <- getPairs(result, single.rows=TRUE, show="links")
    

    但是,这并没有将匹配的列放在一起,而是记录 1 的所有列都跟在记录 2 的所有列之后(最后是匹配权重作为最后一列)。我在这里只显示列名,因为整个表真的很宽:

    > names(matchedPairs)
     [1] "id1"        "Product.1"  "Supplier.1" "UOI.1"      "Price.1"    "id2"        "Product.2"  "Supplier.2" "UOI.2"      "RefPrice.2" "Weight"    
    

    因此,如果您想以这种格式直接进行列与列比较,则必须重新排列列以满足您的需要。

    显然,我需要将配对限制为只有一个权重最高的最佳匹配,但该怎么做呢?

    包不提供此功能,我相信从记录链接结果中选择一对一分配的过程本身需要一些概念上的关注。我从来没有深入到这一步,所以下面可能只是一个开始的想法。您可以使用 data.table 库从具有相同左侧 id 的每组对中选择权重最大的对(比较 How to select the row with the maximum value in each group):

    > library(data.table)
    > matchedPairs <- data.table(matchedPairs)
    > matchedPairs[matchedPairs[,.I[which.max(Weight)],by=id1]$V1, list(id1,id2)]
       id1 id2
    1:   7   5
    2:   5   3
    3:   4   2
    4:   2   6
    5:   6   1
    6:   3   1
    

    这里,list(id1,id2) 将输出限制为记录 ID。

    为了消除右手 id 的双重映射(在这种情况下,1id2 出现两次)您必须对 id2 重复该过程。但是请注意,在某些情况下,在步骤 1 中选择权重最高的对(减少到 id1 的唯一值)可能会删除对于给定值 id2 权重最大的对。因此,为了选择最优的整体映射(例如,最大化所有选择的映射的权重之和),需要一个非贪婪的优化策略。

    更新:对大数据集使用类和方法

    对于大型数据集,可以使用所谓的“大数据”类和方法(请参阅https://cran.r-project.org/web/packages/RecordLinkage/vignettes/BigData.pdf)。这些使用文件支持的数据结构,因此大小限制是可用磁盘空间。语法大多相同,但并不完全相同。对于此示例,实现与上述相同结果的必要调用是:

    rpairs <- RLBigDataLinkage(DOrders, DCatalogue, 
                          blockfld = 3,
                          exclude = 4,
                          strcmp = 1:2,
                          strcmpfun = "jarowinkler")
    
    rpairs <- epiWeights(rpairs)
    result <- epiClassify(rpairs, 0.7)
    matchedPairs <- getPairs(result, single.rows=TRUE, filter.link="link")
    matchedPairs <- data.table(matchedPairs)
    matchedPairs[matchedPairs[,.I[which.max(Weight)],by=id.1]$V1, list(id.1,id.2)]
    

    但是,关于 2 TB 的大小估计,这仍然不可行。我认为您必须通过额外的阻塞来进一步减少对数。

    在这种情况下的问题是包只支持“硬”阻塞标准(即两条记录必须在阻塞字段中完全匹配)。在链接个人数据时(这是我们在开发包时的用例),通常可以组合出生日期的日、月和年组成部分以进行阻止,从而显着减少配对的数量而不会丢失匹配的候选人.据我可以从示例中判断,您的数据不可能进一步“硬”阻塞,因为匹配对只有相似但不相等的属性值(除了您已经使用的“问题单元”阻塞)。像“仅考虑产品名称的字符串相似性大于 [某个阈值] 的对”这样的标准对我来说似乎最合适。为此,您必须扩展 compare.linkage()RLBigDataLinkage()

    【讨论】:

    • 感谢您非常有帮助的回答。不过需要注意的是,根据我的具体目标,我只需要删除 id1 中的双重映射,而不是 id2(即,一个订单只能匹配主参考目录中的一个条目,但目录中的一个条目可以被多次订购)。跨度>
    • 另外,不幸的是,虽然代码在实验性玩具数据集上运行良好,但在真实数据集上根本无法运行。这是因为典型的订单列表具有 c。 150,000 个条目和主目录 400,000 个条目。 R 根本没有足够的内存来创建pairs 对象,这需要c。 30 万亿对。我的大致估计表明,这样的对象将需要 2 Tb 的内存区域。除非有人有任何想法,否则真实数据的链接似乎需要一种完全不同的方法。
    猜你喜欢
    • 1970-01-01
    • 2016-06-30
    • 1970-01-01
    • 1970-01-01
    • 2021-03-19
    • 2019-08-10
    • 1970-01-01
    • 2021-01-29
    • 2018-10-21
    相关资源
    最近更新 更多