我试图使用R包RecordLinkage
来匹配采购订单列表中的项目与主目录中的条目。下面是使用两个虚拟数据集(DOrders和dcatalog)的R代码和一个可重复的示例:
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个条目,每个条目与参考集dcatalog中的9行中的一行匹配。在实际数据中,并非所有订单都匹配。
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
,将价格排除在匹配之外。这将是订单和目录之间的不同之处,也是匹配的主要兴趣所在。使用jarowinkler
字符串比较器(如这里所述)对产品和供应商名称进行匹配:
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)
表明DOrders中的一个条目可以与dcatalog中的多个条目具有高权重匹配。例如
这对配对正确,权重为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
...
首先,感谢您提供了一个可复制的示例,这大大简化了回答您的问题。我将从你的第二个问题开始:
最后,我要寻找的最终结果是一个合并的数据集,其中包含来自订单和目录的匹配条目在一行中,所有列来自两个原始集并排进行比较。
对于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"
所以如果你想在这种格式中直接进行列对列的比较,你必须重新排列列以适应你的需要。
显然,我需要将配对限制为只有一个具有最高权重的最佳匹配,但如何做到这一点?
这个功能不是由包提供的,我相信从记录链接结果中选择一对一分配的过程本身需要一些概念上的注意。我从来没有深入到这一步,所以下面可能只是一个开始的想法。你可以使用这些数据。表库从具有相同左id的每组对中选择权重最大的行(比较如何在每组中选择值最大的行):
> 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的双映射(在本例中,1
为id2
出现两次),您必须对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)]
但是,考虑到您估计的2tb的大小,这仍然是不可行的。我认为你必须通过额外的阻塞来进一步减少对的数量。
这种情况下的问题是包只支持"硬"阻塞标准(即两个记录必须在阻塞字段中完全匹配)。在链接个人数据时(这是我们在开发包时的用例),出生日期的日、月、年组件通常可以组合起来进行阻塞,这样可以显著减少配对的数量,而不会丢失匹配候选项。据我从例子中判断,进一步的"硬"阻塞是不可能的数据,因为匹配对只有相似的,但不等于属性值(除了"问题的单位",你已经用于阻塞)。像"只考虑产品名称的字符串相似度大于[某个阈值]的对"这样的标准对我来说似乎是最合适的。要实现这一点,您必须扩展compare.linkage()
或RLBigDataLinkage()
。