data.table 在非等价自连接上更新的奇怪行为

2024-02-15

在准备一个answer https://stackoverflow.com/a/45781428/3817004对这个问题dplyr 或 data.table 用于计算 R 中的时间序列聚合 https://stackoverflow.com/q/35555314/3817004我注意到,根据表是就地更新还是作为新对象返回,我确实得到了不同的结果。另外,当我更改列中的顺序时,我确实得到了不同的结果非等值连接状况。

目前,我对此没有任何解释,可能是由于我这边的重大误解或简单的编码错误。

请注意,这个问题是特别询问的 对观察到的行为的解释data.table加入。如果你 对于根本问题有替代解决方案,请感受一下 免费发布答案原问题 https://stackoverflow.com/q/35555314/3817004.

原始问题和工作答案

最初的问题是如何使用这些数据统计每个患者住院前 365 天(包括实际住院)的住院次数:

library(data.table)   # version 1.10.4 (CRAN) or 1.10.5 (devel built 2017-08-19)
DT0 <- data.table(
  patient.id = c(1L, 2L, 1L, 1L, 2L, 2L, 2L),
  hospitalization.date = as.Date(c("2013/10/15", "2014/10/15", "2015/7/16", "2016/1/7", 
                                   "2015/12/20", "2015/12/25", "2016/2/10")))
setorder(DT0, patient.id, hospitalization.date)
DT0
   patient.id hospitalization.date
1:          1           2013-10-15
2:          1           2015-07-16
3:          1           2016-01-07
4:          2           2014-10-15
5:          2           2015-12-20
6:          2           2015-12-25
7:          2           2016-02-10

下面的代码给出了预期的答案(为了清楚起见,在此处添加了额外的帮助列)

# add helper columns
DT0[, start.date := hospitalization.date - 365][
  , end.date := hospitalization.date][]
DT0
   patient.id hospitalization.date start.date   end.date
1:          1           2013-10-15 2012-10-15 2013-10-15
2:          1           2015-07-16 2014-07-16 2015-07-16
3:          1           2016-01-07 2015-01-07 2016-01-07
4:          2           2014-10-15 2013-10-15 2014-10-15
5:          2           2015-12-20 2014-12-20 2015-12-20
6:          2           2015-12-25 2014-12-25 2015-12-25
7:          2           2016-02-10 2015-02-10 2016-02-10
result <- DT0[DT0, on = c("patient.id", "hospitalization.date>=start.date", 
              "hospitalization.date<=end.date"), 
   .(hospitalizations.last.year = .N), by = .EACHI][]
result
   patient.id hospitalization.date hospitalization.date hospitalizations.last.year
1:          1           2012-10-15           2013-10-15                          1
2:          1           2014-07-16           2015-07-16                          1
3:          1           2015-01-07           2016-01-07                          2
4:          2           2013-10-15           2014-10-15                          1
5:          2           2014-12-20           2015-12-20                          1
6:          2           2014-12-25           2015-12-25                          2
7:          2           2015-02-10           2016-02-10                          3

除了重命名和重复的列名(保留原样以进行比较)。

For patient.id == 2,最后一行的结果是 3,因为该患者于 2016-02-10 住院,这是自 2015-02-10 以来第三次住院。

关于就地加入的更新

result是一个新的data.table占用额外内存的对象。我尝试更新原来的data.table使用以下方法就位对象:

# use copy of DT0 which can be safely modified
DT <- copy(DT0)

DT[DT, on = c("patient.id", "hospitalization.date>=start.date", 
            "hospitalization.date<=end.date"), 
   hospitalizations.last.year := .N, by = .EACHI]
DT
   patient.id hospitalization.date start.date   end.date hospitalizations.last.year
1:          1           2013-10-15 2012-10-15 2013-10-15                          1
2:          1           2015-07-16 2014-07-16 2015-07-16                          2
3:          1           2016-01-07 2015-01-07 2016-01-07                          2
4:          2           2014-10-15 2013-10-15 2014-10-15                          1
5:          2           2015-12-20 2014-12-20 2015-12-20                          3
6:          2           2015-12-25 2014-12-25 2015-12-25                          3
7:          2           2016-02-10 2015-02-10 2016-02-10                          3

DT现已更新in place但第 5 行和第 6 行分别显示 3 次住院治疗,而不是 1 次或 2 次。现在看来,每一行都返回了最后一段时间内的住院总数。

更改条件中列的顺序。

还有列中的顺序非等值连接即使在自连接中,条件也很重要:

result <- DT0[DT0, on = c("patient.id", "start.date<=hospitalization.date", 
                          "end.date>=hospitalization.date"), 
              .(hospitalizations.last.year = .N), by = .EACHI][]
result

我的期望是"start.date<=hospitalization.date"将相当于"hospitalization.date>=start.date"(请注意,还< and >被切换)但结果

   patient.id start.date   end.date hospitalizations.last.year
1:          1 2013-10-15 2013-10-15                          1
2:          1 2015-07-16 2015-07-16                          2
3:          1 2016-01-07 2016-01-07                          1
4:          2 2014-10-15 2014-10-15                          1
5:          2 2015-12-20 2015-12-20                          3
6:          2 2015-12-25 2015-12-25                          2
7:          2 2016-02-10 2016-02-10                          1

是不同的。看来现在正在统计即将住院的人数

有趣的是,这次更新in place现在返回相同的结果(除了某些列名称):

# use copy of DT0 which can be safely modified
DT <- copy(DT0)
DT[DT, on = c("patient.id", "start.date<=hospitalization.date", 
              "end.date>=hospitalization.date"), 
   hospitalizations.last.year := .N, by = .EACHI]
DT
   patient.id hospitalization.date start.date   end.date hospitalizations.last.year
1:          1           2013-10-15 2012-10-15 2013-10-15                          1
2:          1           2015-07-16 2014-07-16 2015-07-16                          2
3:          1           2016-01-07 2015-01-07 2016-01-07                          1
4:          2           2014-10-15 2013-10-15 2014-10-15                          1
5:          2           2015-12-20 2014-12-20 2015-12-20                          3
6:          2           2015-12-25 2014-12-25 2015-12-25                          2
7:          2           2016-02-10 2015-02-10 2016-02-10                          1

Related

有一个潜在的相关问题 https://stackoverflow.com/q/45212781/3817004这导致了github 上报告的问题 https://github.com/Rdatatable/data.table/issues/2275.

有一个阿伦的回答 https://stackoverflow.com/a/44343424/3817004关于使用x.前缀为非等值连接.


分组情况by=.EACHI意思是“按每个 i”而不是“按每个 x”。

# for readability / my sanity
DT = copy(DT0)
setnames(DT, "hospitalization.date", "h.date")

z = DT[DT, on = .(patient.id, h.date >= start.date, h.date <= end.date), 
   .(x.h.date, patient.id, i.start.date, i.end.date, g = .GRP, .N)
, by=.EACHI][, utils:::tail.default(.SD, 6)]

      x.h.date patient.id i.start.date i.end.date g N
 1: 2013-10-15          1   2012-10-15 2013-10-15 1 1 * 
 2: 2015-07-16          1   2014-07-16 2015-07-16 2 1 
 3: 2015-07-16          1   2015-01-07 2016-01-07 3 2 *
 4: 2016-01-07          1   2015-01-07 2016-01-07 3 2 *
 5: 2014-10-15          2   2013-10-15 2014-10-15 4 1 *  
 6: 2015-12-20          2   2014-12-20 2015-12-20 5 1
 7: 2015-12-20          2   2014-12-25 2015-12-25 6 2  
 8: 2015-12-25          2   2014-12-25 2015-12-25 6 2 
 9: 2015-12-20          2   2015-02-10 2016-02-10 7 3 *
10: 2015-12-25          2   2015-02-10 2016-02-10 7 3 *
11: 2016-02-10          2   2015-02-10 2016-02-10 7 3 *

对于患者 1,各组为

  • .(start.date = 2012-10-15, end.date = 2013-10-15), 计数 1
  • .(start.date = 2014-07-16, end.date = 2015-07-16), 计数 1
  • .(start.date = 2015-01-07, end.date = 2016-01-07), 计数 2

幸运的是,此连接中有七个组,原始表中有七行。

对于更棘手的问题,我将借用我笔记中的一个例子:

请注意更新连接中的多个匹配项。当存在多个匹配项时,更新联接显然只会使用最后一个匹配项。不幸的是,这是悄然进行的。尝试:

a = data.table(id = c(1L, 1L, 2L, 3L, NA_integer_), 
  t = c(1L, 2L, 1L, 2L, NA_integer_), x = 11:15)
b = data.table(id = 1:2, y = c(11L, 15L))
b[a, on=.(id), x := i.x, verbose = TRUE ][]

# Calculated ad hoc index in 0 secs
# Starting bmerge ...done in 0.02 secs
# Detected that j uses these columns: x,i.x 
# Assigning to 3 row subset of 2 rows
#    id  y  x
# 1:  1 11 12
# 2:  2 15 13

打开 verbose 后,我们会看到一条有关分配“至 2 行的 3 行子集”的有用消息。

-- 修改自“快速 R 教程”,“在联接中更新”部分 http://franknarf1.github.io/r-tutorial/_book/tables.html#joins-update

就OP而言,verbose=TRUE does not不幸的是,提供了这样的信息。

DT[DT, on = .(patient.id, h.date >= start.date, h.date <= end.date), 
   n := .N, by = .EACHI, verbose=TRUE]
# Non-equi join operators detected ... 
#   forder took ... 0.01 secs
#   Generating group lengths ... done in 0 secs
#   Generating non-equi group ids ... done in 0 secs
#   Found 1 non-equi group(s) ...
# Starting bmerge ...done in 0.02 secs
# Detected that j uses these columns: <none> 
# lapply optimization is on, j unchanged as '.N'
# Making each group and running j (GForce FALSE) ... 
#   memcpy contiguous groups took 0.000s for 7 groups
#   eval(j) took 0.000s for 7 calls
# 0.01 secs

但是,我们可以看到每行的最后一行xgroup 确实包含 OP 看到的值。我已在上面手动用星号标记了这些。或者,您可以用以下标记来标记它们z[, mrk := replace(rep(0, .N), .N, 1), by=x.h.date].


作为参考,这里的更新连接是...

DT[, n := 
  .SD[.SD, on = .(patient.id, h.date >= start.date, h.date <= end.date), .N, by=.EACHI]$N 
]

   patient.id hospitalization.date start.date   end.date     h.date n
1:          1           2013-10-15 2012-10-15 2013-10-15 2013-10-15 1
2:          1           2015-07-16 2014-07-16 2015-07-16 2015-07-16 1
3:          1           2016-01-07 2015-01-07 2016-01-07 2016-01-07 2
4:          2           2014-10-15 2013-10-15 2014-10-15 2014-10-15 1
5:          2           2015-12-20 2014-12-20 2015-12-20 2015-12-20 1
6:          2           2015-12-25 2014-12-25 2015-12-25 2015-12-25 2
7:          2           2016-02-10 2015-02-10 2016-02-10 2016-02-10 3

这是处理这种情况的正确/惯用方法,将列添加到x基于查找每一行x在另一个表中并计算结果摘要:

x[, v := DT2[.SD, on=, j, by=.EACHI]$V1 ]
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

data.table 在非等价自连接上更新的奇怪行为 的相关文章

  • R中添加水印

    我在用magickR中的库 我想在一些图片上添加水印 I used image annotate功能如下 img lt image read C Users Maydin Desktop manzara png image annotate
  • decompose() 的周期太少[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 错误看起来像这样 decompose
  • ggplot2可以在一个图例中分别控制点大小和线大小(线宽)吗?

    一个使用的例子ggplot2绘制数据点组和连接每组均值的线 并使用相同的映射aes for shape并为linetype p lt ggplot mtcars aes gear mpg shape factor cyl linetype
  • R 中具有稳健回归的异常值

    我正在使用lmrobR 中的函数使用robustbase用于稳健回归的库 我会把它用作 rob reg lt lmrob y 0 dat method MM control a1 当我想返回我使用的摘要时summary rob reg 稳健
  • mySQL MATCH 跨多个表

    我有一组 4 个表 我想对其进行搜索 每个都有全文索引 查询可以使用每个索引吗 CREATE TABLE categories id int 5 unsigned NOT NULL auto increment display order
  • 计算例如具有多列 data.frames 的列表中的平均值

    我有几个 data frames 的列表 每个 data frame 有几列 通过使用mean mylist first dataframe a我可以得到这个 data frame 中 a 的平均值 但是我不知道如何计算列表中存储的所有 d
  • 如何在R中删除重复项

    我有一个非常大的数据集 如下所示 df lt data frame school c a a a b b c c c year c 3 3 1 4 2 4 3 1 GPA c 4 4 4 3 3 3 2 2 school year GPA
  • 在shiny中过滤传单地图数据

    我在用传单地图设置这个闪亮的东西时遇到了麻烦 我的原帖 https stackoverflow com questions 50111566 applying leaflet map bounds to filter data within
  • R foreach问题(某些进程返回NULL)

    我遇到了问题foreach我正在 R 中使用的程序的一部分 该程序用于运行不同参数的模拟 然后将结果返回到单个列表 然后用于生成报告 当并非所有分配的模拟运行都在报告上实际可见时 就会出现问题 从各方面来看 似乎只有分配的运行的一个子集实际
  • 我无法下载 R 中的 reshape2 包 [关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 我在尝试安装 R 包时收到此响应 gt installed packages reshape2 Package LibPath V
  • 使用 purrr 迭代替换数据帧列中的字符串

    我想用purrr使用以下命令在数据框列上迭代运行多个字符串替换gsub 功能 这是示例数据框 df lt data frame Year 2019 Text c rep a aa 5 rep a bb 3 rep a cc 2 gt df
  • 通过间接引用列来修改数据框中的某些值

    我正在整理一些数据 我们将失败的数据分类到垃圾箱中 并按批次计算每个分类箱的有限产量 我有一个描述排序箱的元表 这些行按升序测试顺序排列 一些排序标签带有非语法名称 sort tbl lt tibble tribble weight lab
  • 将绘图调用拆分为多个块

    我正在编写一个图的解释 其中我基本上将在第一个块中创建图 然后描述该输出 并在第二个块中添加一个轴 然而 似乎每个块都会强制一个新的绘图环境 因此当我们尝试使用以下命令运行块时会出现错误axis独自的 观察 output html docu
  • 绘制点之间的所有线

    我有以下 R 代码 x lt c 0 01848598 0 08052353 0 06741172 0 11652034 y lt c 0 4177541 0 4042247 0 3964025 0 4074685 d lt data fr
  • 当sql连接中存在两个同名列时,如何从一个表列中获取值

    当我连接两个具有相同名称列的表时 我目前面临着尝试获取值的问题 例如 table1 date和table2 date 每个表中的日期不同 我将如何获取 日期 本例中的表1 我目前正在跑步 while row mysqliquery gt f
  • 以引用透明的方式从函数的省略号参数中提取符号

    事情又发生了 我正要按下发布答案按钮的问题被删除了 我正在寻找一种方法来从函数的省略号参数中提取绑定到符号的对象的值以及符号 也就是说 我试图以引用透明的方式从省略号中提取符号 我尝试过使用替代品和lazy dots 但没有成功 funct
  • r 中训练和测试数据的最小最大缩放/归一化

    我正在创建一个函数 它将训练集和测试集作为其参数 最小 最大缩放 标准化并返回训练集并使用这些same最小值和最小 最大范围的值 标准化并返回测试集 到目前为止 这是我想出的功能 min max scaling lt function tr
  • 朴素贝叶斯分类器仅基于先验概率做出决策

    我试图根据推文的情绪将推文分为三类 买入 持有 卖出 我正在使用 R 和包 e1071 我有两个数据框 一个训练集和一组需要预测情绪的新推文 训练集数据框 text sentiment this stock is a good buy Bu
  • 只读取选定的列

    谁能告诉我如何仅读取下面每年数据的前 6 个月 7 列 例如使用read table Year Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec 2009 41 27 25 31 31 39 2
  • 如何仅删除单括号并保留配对的括号

    你好 我亲爱的老师 R 用户朋友们 我最近开始认真学习正则表达式 最近我遇到了一种情况 我们只想保留配对括号 并省略未配对的 这是我的样本数据 structure list t1 c Book Pg 1 Website Online Jou

随机推荐

  • 避免快速自动链接框架

    我有一个示例项目 https github com Usipov SwiftAutoFrameworksLinkage由一个主要目标 LinkerTests 和一个依赖的动态框架 Dynamic 如果运行该项目 您将看到以下 dyld 二进
  • 通过 angularjs 中的路由进行重定向

    我有以下要求 应显示包含编辑和删除链接的所有项目的列表 当用户单击编辑时 应出现带有文本框和保存按钮的编辑表单 现在 当用户编辑数据并单击保存按钮时 应保存数据 并且列表页面应再次显示修改后的数据 一切正常 但我如何通过 AngularJS
  • SQL Server使用C#执行备份

    我研究了使用 C 通过 SMO 创建数据库备份的可能性 该任务非常简单 代码也很简单 我只有一个问题 如何检查备份是否真正创建 Sql备份 Sql备份 http msdn microsoft com en us library micros
  • 如何在不使用 QtCreator 的情况下将 dll 文件复制到 Qt 中的输出目录?

    我有一个基于 Qt 的应用程序 它使用许多在项目外部构建的 dll 这些 dll 被签入源代码 因为我们不会非常频繁地重建它们 它们需要几个小时才能构建 我不希望它们出现在主项目中 我想在构建完成后将这些 dll 复制到适当的目录 发布 调
  • Powershell 表达式没有给出结果

    我创建了一个应返回 OU 规范名称的表达式 一个小轮廓 Search ADAccount LockedOut UsersOnly Select Object Name SamAccountName Name OU Expression Ge
  • 在 Django 中将变量从模板传递到视图的更有效方法是什么?

    我的问题涉及将变量从模板传递到 Django 中查看 我知道如何在 URL 中以及通过表单传递变量 我遇到的第一个问题是 url 可以被操纵 这不是我想要的 有什么办法可以防止这种情况发生吗 现在这就是我的创可贴
  • 如何编写一个使用 image magick 将图像切成碎片的 bash 脚本?

    我有许多输入图像 其中包含多个较小的图像 所有图像都位于一行中 所有包含的图像尺寸相同 因此 例如 图像input png may be 480x48并包含 1048x48图像 全部排成一排 使用imagemagickconvert工具 或
  • 卸载App后如何删除数据?

    我正在开发一个 Android 应用程序 它在 SD 卡中创建一个文件夹并存储一些图像 我想在卸载应用程序时删除该文件夹 请指导我 简单 不可能 目前 当您自己的应用程序被卸载时 不会触发卸载事件 因此你无法以任何方式对此做出反应 唯一的例
  • jQuery/Ajax 加载的 DOM 脚本何时实际执行?

    好吧 我觉得问这个问题有点愚蠢 类似问题有很多点击 但我似乎无法回答正确 如果我通过 jQuery Ajax 修改 DOM 加载的脚本何时实际解析 执行 下面的代码适用于 F F 但不适用于 Chrome 或 Opera 工作 意味着它执行
  • App Engine 无缓存 JSP

    我想在我的 Google 应用引擎网站上禁用 JSP 文件的缓存 我有这个
  • SIMD 或非 SIMD - 跨平台

    我需要一些想法如何编写一些可并行问题的 C 跨平台实现 以便我可以利用 SIMD SSE SPU 等 如果可用 我希望能够在运行时在 SIMD 和非 SIMD 之间切换 您建议我如何解决这个问题 当然我不想针对所有可能的选项多次实现该问题
  • 如何在java servlet中限制上传速度?

    我正在开发一个应用程序 基于 Spring 作为 DI 和 MVC 框架 该应用程序具有文件上传功能 该功能当前使用 Spring Multipart Upload 实现 反过来又利用公共文件上传库 所以我正在寻找一种降低上传带宽消耗的方法
  • 在 ngx-bootstrap 模式中向 onHide 事件发送参数

    我正在使用组件作为模板打开一个模式 一切正常 模式打开 我正在订阅 onHide 事件 订阅也有效 但我在这里面临一个挑战 我想发送一个特定的原因 例如 消息添加成功 作为原因 我怎样才能做到这一点 如何发送特定字符串作为原因 目前 我尝试
  • 正则表达式非贪婪是贪婪

    我有以下文字 tooooooooooooon 根据我正在读的这本书 当 跟在任何量词之后 它就变得非贪婪的 我的正则表达式to n仍在返回tooooooooooooon 它应该返回ton不应该吗 知道为什么吗 正则表达式只能匹配实际存在的文
  • 尝试注销 django 时出现运行时错误

    当我尝试从 django 项目注销时 出现以下错误 调用 Python 对象时超出最大递归深度 这是注销按钮的 URL url r logout users views logout name logout 这是视图 from django
  • 将自定义工具提示添加到 DataGrid 中的行

    我想自定义我的 DataGrid 以在所选行中显示工具提示 请参阅下面的模型图像以更好地了解我想要实现的目标 As it is at the moment Shows a single selected row 我多么愿意 显示选定的同一行
  • 复杂的 nHibernate QueryOver 表达式

    我在层次结构中有以下对象A gt B gt C gt D 每个对象都映射到一个表 我正在尝试使用 QueryOver 编写以下 SQL SELECT B FROM A B C D WHERE A ID B ID AND B ID C ID
  • 由于 ToList() 不起作用而返回视图

    我有这个代码 EmployeeEntities storeDB new EmployeeEntities public ActionResult Index var employee storeDB Employees ToList ToL
  • SQL Server 2005 执行MySQL REPLACE INTO?

    MySQL 有这个非常有用但专有的功能REPLACE INTOSQL 命令 这可以在 SQL Server 2005 中轻松模拟吗 开始一个新的事务 执行Select 然后要么UPDATE or INSERT and COMMIT总是有点痛
  • data.table 在非等价自连接上更新的奇怪行为

    在准备一个answer https stackoverflow com a 45781428 3817004对这个问题dplyr 或 data table 用于计算 R 中的时间序列聚合 https stackoverflow com q