【问题标题】:Non-equi join using data.table: column missing from the output使用 data.table 的非 equi 连接:输出中缺少列
【发布时间】:2017-11-01 02:20:32
【问题描述】:

我正在使用data.table 进行左非等连接:

OUTPUT <- DT2[DT1, on=.(DOB, FORENAME, SURNAME, POSTCODE, START_DATE <= MONTH, EXPIRY_DATE >= MONTH)]

OUTPUT 包含正确的左连接,但缺少 MONTH 列(存在于 DT1 中)除外。

这是data.table 中的错误吗?

NB:当然,START_DATEEXPIRY_DATEMONTH 是相同的 YYYY-MM-DD、IDate 格式。根据这些非 equi 标准,连接的结果是正确的。只是缺少该列,我需要在进一步的工作中使用它。

编辑 1:简化的可重现示例

DT1 <- structure(list(ID = c(1, 2, 3), FORENAME = c("JOHN", "JACK", 
"ROB"), SURNAME = c("JOHNSON", "JACKSON", "ROBINSON"), MONTH = structure(c(16953L, 
16953L, 16953L), class = c("IDate", "Date"))), .Names = c("ID", 
"FORENAME", "SURNAME", "MONTH"), row.names = c(NA, -3L), class = c("data.table", 
"data.frame"))

DT2 <- structure(list(CERT_NUMBER = 999, FORENAME = "JOHN", SURNAME = "JOHNSON", 
    START_DATE = structure(16801L, class = c("IDate", "Date")), 
    EXPIRY_DATE = structure(17166L, class = c("IDate", "Date"
    ))), .Names = c("CERT_NUMBER", "FORENAME", "SURNAME", "START_DATE", 
"EXPIRY_DATE"), row.names = c(NA, -1L), class = c("data.table", 
"data.frame"))

OUTPUT <- DT2[DT1, on=.(FORENAME, SURNAME, START_DATE <= MONTH, EXPIRY_DATE >= MONTH)]

> OUTPUT
   CERT_NUMBER FORENAME  SURNAME START_DATE EXPIRY_DATE ID
1:         999     JOHN  JOHNSON 2016-06-01  2016-06-01  1
2:          NA     JACK  JACKSON 2016-06-01  2016-06-01  2
3:          NA      ROB ROBINSON 2016-06-01  2016-06-01  3
  • FORENAMESURNAME 加入并出现在输出中。
  • MONTH 也(非 equi)加入,并且在输出中不存在。

为什么会出现这种预期行为?

即使这是预期的行为,对我的情况也没有帮助,因为我需要保留 MONTH 以进行进一步的数据操作。

我的预期输出将是同一张表,但 MONTH 列仍保留在 DT1 中。毕竟,我对左连接的期望是从左表 (DT1) 中保留每一行和每一列,并从右表 (DT2) 中添加所有列和仅匹配的行。

   CERT_NUMBER FORENAME  SURNAME START_DATE EXPIRY_DATE ID      MONTH
1:         999     JOHN  JOHNSON 2016-01-01  2016-12-31  1 2016-06-01
2:          NA     JACK  JACKSON       <NA>        <NA>  2 2016-06-01
3:          NA      ROB ROBINSON       <NA>        <NA>  3 2016-06-01

编辑 2:显然在我的代码产生的输出中,START 和 END 日期也是错误的!只有人 1 的证书开始日期为 1 月 1 日,结束日期为 12 月 31 日!预期的输出是应该的。但实际输出是 1 月 1 日。

【问题讨论】:

  • 提供reproducible example 总是好的。就目前的问题而言,人们很难看出哪里出了问题。
  • 除了 MONTH 列(DT1 中存在)缺失之外,是什么意思OUTPUT 中是否缺少它?如果这是您的问题:这是正常行为,因为您正在加入它。因此,OUTPUT 将有 START_DATEEXPIRY_DATE,但没有 MONTH,因为它是与其他两个进行比较的。
  • @Jaap:是的,这正是正在发生的事情。但是,OUTPUT 仍然包含DOBFORENAMESURNAMEPOSTCODE,并且这些列也正在加入。是否有调整以保留 MONTH 列?
  • 不确定,但您可以尝试OUTPUT &lt;- DT2[DT1, on=.(DOB, FORENAME, SURNAME, POSTCODE, START_DATE &lt;= MONTH, EXPIRY_DATE &gt;= MONTH), MONTH := i.MONTH]。但正如我在之前的评论中所说:没有reproducible example 很难测试。

标签: r join data.table left-join


【解决方案1】:

在 data.table 中,x[i] 形式的联接传统上使用来自 i 的值,但使用来自 x 的列名。尽管这与返回两者的 SQL 不同,但此默认值对于 equi 连接很有意义,因为我们对来自 i 的所有行感兴趣,如果它们匹配,则两个 data.tables 都有 equal 值,如果不是,我们需要在结果中保留来自i 的那些不匹配的值。

但是对于 non-equi 连接,由于值可能不匹配类似于 SQL 的输出(或识别此类情况并返回用户期望的结果,类似于 equi 连接的情况)。这还没有完成,但我现在已经为它做了一个规定,即使用 x. 前缀显式引用列。这不方便,我同意。希望这会很快自动处理。

以下是使用 x. 前缀获取结果的方法。

ans <- DT2[DT1, .(CERT_NUMBER, FORENAME, SURNAME, x.START_DATE, x.EXPIRY_DATE, ID, MONTH), 
         on=.(FORENAME, SURNAME, START_DATE <= MONTH, EXPIRY_DATE >= MONTH)]

IIRC 在 GitHub 项目页面上也有关于此的问题。

【讨论】:

  • 谢谢 - 这对我有用,似乎确实是解决这个问题的方法!
  • 最新版本的data.table是否解决了这个问题?或者我怎样才能用最新版本解决这个问题?
猜你喜欢
  • 2017-05-29
  • 1970-01-01
  • 2021-05-28
  • 2020-09-30
  • 1970-01-01
  • 2016-05-14
  • 1970-01-01
  • 2018-01-29
  • 1970-01-01
相关资源
最近更新 更多