【问题标题】:Doing a "fuzzyjoin" (and non-fuzzyjoin) in combination with a merge in data.table结合 data.table 中的合并进行“模糊连接”(和非模糊连接)
【发布时间】:2019-05-24 16:24:23
【问题描述】:

我正在使用多个数据库。对于这些数据库中的每一个,我都创建了一个名为matchcode 的密钥。这个matchcode 是国家代码和年份的组合。大多数情况下,当我合并这些数据集时,我只是这样做:

dfA<- merge(dfA, dfB, by= "matchcode", all.x = TRUE, allow.cartesian=FALSE)

问题是有时年份不完全匹配:

   dfA <- read.table(
  text = "A   B   C   D   E   F   G   iso   year   matchcode
  1   0   1   1   1   0   1   0   NLD   2010   NLD2010
  2   1   0   0   0   1   0   1   NLD   2014   NLD2014
  3   0   0   0   1   1   0   0   AUS   2010   AUS2010
  4   1   0   1   0   0   1   0   AUS   2006   AUS2006
  5   0   1   0   1   0   1   1   USA   2008   USA2008
  6   0   0   1   0   0   0   1   USA   2010   USA2010
  7   0   1   0   1   0   0   0   USA   2012   USA2012
  8   1   0   1   0   0   1   0   BLG   2008   BLG2008
  9   0   1   0   1   1   0   1   BEL   2008   BEL2008
  10   1   0   1   0   0   1   0  BEL   2010   BEL2010",
  header = TRUE
)

   dfB <- read.table(
  text = "K   L   M   N   O   P   Q   iso   year   matchcode
  1   0   1   1   1   0   1   0   NLD   2009   NLD2009
  2   1   0   0   0   1   0   1   NLD   2014   NLD2014
  3   0   0   0   1   1   0   0   AUS   2011   AUS2011
  4   1   0   1   0   0   1   0   AUS   2007   AUS2007
  5   0   1   0   1   0   1   1   USA   2007   USA2007
  6   0   0   1   0   0   0   1   USA   2011   USA2010
  7   0   1   0   1   0   0   0   USA   2013   USA2013
  8   1   0   1   0   0   1   0   BLG   2007   BLG2007
  9   0   1   0   1   1   0   1   BEL   2009   BEL2009
  10   1   0   1   0   0   1   0  BEL   2012   BEL2012",
  header = TRUE
)

我正在寻找一个类似于以下answer by Jaap 的 data.table 解决方案:

library(data.table)
setDT(dfA)
setDT(dfB)

dfA[dfB
       , on = .(iso, year)
       , roll = "nearest"
       , .(ID, year.x = i.year, year.y = x.year, value, delta = abs(i.year- x.year))]

但是,除了这个解决方案之外,我还想:

  1. 将两个数据库的所有列都放在新的 data.table 中。
  2. 将滚动限制为+1 | -1。但是,当我输入它时,它似乎没有正确应用它。

对于 1. 我显然需要使用 mget,again thanks to Jaap

dfA[dfB, on = .(iso, year), names(dfB)[1:10] := 
        mget(paste0("i.", names(dfB)[1:10]))]

但是,我似乎无法成功地将其组合在一起。我试过了:

dfA[dfB, on = .(iso, year), roll = "nearest", names(dfB)[1:10] := 
   mget(paste0("i.", names(dfB)[1:10])),
   .(matchcode, year.x = i.year, year.y = x.year, delta = abs(i.year - x.year))]

但这给出了:

Error in eval(bysub, xss, parent.frame()) : object 'i.year' not found.

以下是有效的:

 dfA[dfB
     , on = .(iso, year)
     , roll = "nearest"
     , .(matchcode, year.x = i.year, year.y = x.year, delta = abs(i.year - x.year))]
    matchcode year.x year.y delta
 1:   NLD2010   2009   2010     1
 2:   NLD2014   2014   2014     0
 3:   AUS2010   2011   2010     1
 4:   AUS2006   2007   2006     1
 5:   USA2008   2007   2008     1
 6:   USA2010   2011   2010     1
 7:   USA2012   2013   2012     1
 8:   BLG2008   2007   2008     1
 9:   BEL2008   2009   2008     1
10:   BEL2010   2012   2010     2

对如何进行有什么建议吗?

【问题讨论】:

    标签: r merge datatable fuzzyjoin


    【解决方案1】:

    希望这对你有用:

    dfA[, yearA := year]
    
    res1 <- dfA[dfB, on = .(iso, year), roll = 1, nomatch = 0]
    res2 <- dfA[dfB, on = .(iso, year), roll = -1, nomatch = 0]
    res <- rbind(res1, res2[yearA > year])
    setnames(res, c('year', 'matchcode', 'i.matchcode'), c('yearB', 'matchcodeA', 'matchcodeB'))
    
    #    A B C D E F G iso yearB matchcodeA yearA K L M N O P Q matchcodeB
    # 1: 1 0 0 0 1 0 1 NLD  2014    NLD2014  2014 1 0 0 0 1 0 1    NLD2014
    # 2: 0 0 0 1 1 0 0 AUS  2011    AUS2010  2010 0 0 0 1 1 0 0    AUS2011
    # 3: 1 0 1 0 0 1 0 AUS  2007    AUS2006  2006 1 0 1 0 0 1 0    AUS2007
    # 4: 0 0 1 0 0 0 1 USA  2011    USA2010  2010 0 0 1 0 0 0 1    USA2010
    # 5: 0 1 0 1 0 0 0 USA  2013    USA2012  2012 0 1 0 1 0 0 0    USA2013
    # 6: 0 1 0 1 1 0 1 BEL  2009    BEL2008  2008 0 1 0 1 1 0 1    BEL2009
    # 7: 0 1 1 1 0 1 0 NLD  2009    NLD2010  2010 0 1 1 1 0 1 0    NLD2009
    # 8: 0 1 0 1 0 1 1 USA  2007    USA2008  2008 0 1 0 1 0 1 1    USA2007
    # 9: 0 1 0 1 0 0 0 USA  2011    USA2012  2012 0 0 1 0 0 0 1    USA2010
    # 10: 1 0 1 0 0 1 0 BLG  2007    BLG2008  2008 1 0 1 0 0 1 0    BLG2007
    # 11: 1 0 1 0 0 1 0 BEL  2009    BEL2010  2010 0 1 0 1 1 0 1    BEL2009
    

    【讨论】:

    • 感谢 mt1022!非常有趣的解决方案!但是,我确实收到了尚未指定 yearA 的错误 Error in .checkTypos(e, names(x)) : Object 'yearA' not found. Perhaps you intended year 。我以为您可能打算添加类似colnames(res1)[9]&lt;-"yearA" 的内容,但这不起作用哈哈..
    • @Tom,抱歉,从工作室复制粘贴时错过了一行 :(。现已修复。
    • 非常感谢 mt1022。还有一件事。我注意到 USA 2011 现在匹配了两次,一次与 2010 年和 2012 年匹配。是否有优先选择其中之一?我尝试使用&gt; 标志,但这并没有帮助。对于手头的示例,可以简单地删除 matchcodeA 中的重复项,但是由于我的实际数据集,这不起作用(因为 matchcodeA 并不意味着在数据集中是唯一的)。
    • @Tom,一种可能的方法是通过dfA[, rowA := 1:.N]dfA 添加一个新列。加入后,您可以通过删除重复的 rowA 值来确保 A 中的每一行仅使用一次。
    • 再次感谢!这应该可行,因为dfA 通常应该在数据集中的某处具有唯一 ID。你帮了大忙,非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    • 1970-01-01
    • 1970-01-01
    • 2018-07-25
    • 2017-01-31
    • 1970-01-01
    相关资源
    最近更新 更多