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 在非等价自连接上更新的奇怪行为 的相关文章

  • 如何合并具有相同列名的数据框

    我有一个数据框 如下所示 structure list Variables structure list ADA ADA LEAD LEAD BIG4 BIG4 LOGMKT LOGMKT LEV LEV ROA ROA ROAL ROAL
  • 将数据框中的 1 列拆分为 2 列 [重复]

    这个问题在这里已经有答案了 这是我的数据框 gt data Manufacturers 1 Audi RS5 2 BMW M3 3 Cadillac CTS V 4 Lexus ISF 所以我想将制造商和型号分开 就像这样 gt data
  • R data.table:在当前测量之前对出现次数进行计数

    我有一组在几天内进行的测量结果 测量次数通常为 4 任何测量中可以捕获的数字范围为 1 5 在现实生活中 给定测试集 范围可能高达 100 或低至 20 我想每天计算每个值在当天之前发生的次数 让我用一些示例数据来解释 test data
  • rle 命令帮助

    我在使用 rle 命令时遇到了一些麻烦 该命令旨在找到参与者连续达到 8 个连续参与者的点 例如 如果 x lt c 0 1 0 1 1 1 1 1 1 1 1 1 我想返回值 11 感谢 DWin 我一直在使用这段代码 which rle
  • R - 对矩阵的每行/列应用具有不同参数值的函数

    我试图将函数应用于矩阵的每一行或每一列 但我需要为每一行传递不同的参数值 我以为我熟悉 lapply mapply 等 但可能还不够 举个简单的例子 gt a lt matrix 1 100 ncol 10 gt a 1 2 3 4 5 6
  • R 如何按行值进行分组、拆分或子集

    这是上一个问题的延续R 如何按行值分组 分裂 https stackoverflow com questions 64602607 r how to group by row value split 输入数据帧的变化是 id str c x
  • 将日期刻度添加到 R 中的 ggplot

    我试图在此图中的 x 轴上添加刻度以显示一年中的所有月份 我的代码如下 library ggplot2 library scales p lt ggplot df test aes time reading p geom point alp
  • 寻找一种有效的方法来计算两个表中间隔集之间的重叠数量?

    注意 为了方便起见 我使用上一篇文章中的示例数据集 假设有两个数据集 ref and map 他们是 ref lt data table space rep nI 3 t1 c 100 300 500 t2 c 150 400 600 id
  • 按元素名称组合/合并列表

    我有两个列表 其元素的名称部分重叠 我需要将其逐个元素合并 组合成一个列表 gt lst1 lt list integers c 1 7 letters letters 1 5 words c two strings gt lst2 lt
  • 使用 geom_abline() 和 ggplot

    我是初学者ggplot2 距离我开始试验才过去 4 天 所以 如果这个问题听起来太基本了 我深表歉意 我很感激任何指导 我已经在这个问题上苦苦挣扎了大约一个小时 我正在尝试使用geom abline 如下 p lt ggplot mpg a
  • 三角形内的热图

    考虑以下示例 triangle lines lt data frame X c 0 0 1 1 0 5 0 5 Y c 0 0 0 0 1 1 grp c 1 2 1 3 2 3 df lt matrix c c 0 2 0 5 0 8 c
  • 在 R 中绘制 3D 数据

    我有一个 3D 数据集 data data frame x rep c 0 1 0 2 0 3 0 4 0 5 each 5 y rep c 1 2 3 4 5 5 data z runif 25 min data x data y 0 1
  • 包含多行 LaTeX 方程的 R 帮助页面

    我正在编写 R 包文档roxygen2 我想将以下多行方程插入到帮助页面中 但我的 LaTeX 代码没有被渲染 hello2 description deqn F t begin cases alpha t f L t 1 alpha t
  • 调试 Littler/Rscripts

    我该如何调试Rscripts从命令行运行 我目前正在使用getopt包来传递命令行选项 但当出现错误时 我很难 看看到底出了什么问题 交互式调试R 因为脚本需要命令行选项 有人有示例代码并愿意分享吗 您可以使用 args 将命令行参数传递到
  • 从上一列中减去一列

    样本数据 dfData lt data frame ID c 1 2 3 4 5 DistA c 10 8 15 22 15 DistB c 15 35 40 33 20 DistC c 20 40 50 45 30 DistD c 60
  • 通过 read.big.matrix 读取 R 中的大数据

    我正在使用 r 读取尺寸为 3131875 5 的数据read big matrix 我的数据既有字符列又有数字列 包括日期变量 我应该使用的命令是 as1 lt read big matrix C Documents and Settin
  • 读取 csv 文件时出错

    我有一个 xlsx 文件 为了从 Rstudio 读取 我将其保存为 csv 文件 现在 当我尝试从 Rstudio 读取文件时 收到以下错误 setwd D DATA SCIENCE CCPP Linear regression ccpp
  • dplyr:评估错误:对象“。”在 gamlss 中找不到,但在 lm、gam、glm 方法中都很好

    语境 tidyverse and dplyr环境 工作流程 我希望了解如何解决以下问题 这是我在尝试处理回归结果集合时遇到的 这个最小的可重复性显示了问题 mtcars gt gamlss mpg hp wt disp data gt mo
  • 优化对绑定到 DataGridView 的 DataTable 的更新

    我的应用程序中有一个显示一些数据的表单 当我第一次显示表单时 我将一些数据加载到 DataTable 中 然后将 DataTable 绑定到 DataGridView 我还启动了一个异步方法来执行一些较慢的数据库查询 当这些慢查询完成时 我
  • 如何在R中生成多个矩阵

    我在 R 中得到了两个值列表 daily max car List 1 21 21 22 22 22 22 21 daily 0 8 List 2 16 17 17 17 18 17 17 尝试在 R Studio 中编写一个 For 循环

随机推荐

  • 避免快速自动链接框架

    我有一个示例项目 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