【问题标题】:Loop through grouped data and perform循环分组数据并执行
【发布时间】:2017-07-17 09:49:34
【问题描述】:

假设我有以下示例:

我的原始数据集包括从VisitLinkDis 3 的变量。我想创建一个新的变量new,这样当我按Patient 对数据进行分组时,回顾该患者就诊前的20 天,检查Dis1 在当时的任何一次就诊中是否为真。我想要的new 是:

我做了几次尝试,但他们都忽略了分组。

Patient DaysToEvent  Dis1  Dis2  Dis3   new
      1         130  TRUE FALSE FALSE  TRUE
      1         135 FALSE FALSE FALSE  TRUE
      2         456  TRUE  TRUE FALSE  TRUE
      2         500 FALSE FALSE FALSE  FALSE
      2         550  TRUE FALSE FALSE  TRUE
      2         560 FALSE  TRUE  TRUE  TRUE
      3         200 FALSE FALSE FALSE  FALSE
      3         400  TRUE  TRUE FALSE  TRUE
      3         410 FALSE  TRUE FALSE  TRUE
      3         510 FALSE FALSE FALSE  FALSE
      4           1  TRUE FALSE FALSE  TRUE
      4          20 FALSE  TRUE FALSE  TRUE
      4         110 FALSE FALSE FALSE  FALSE

谢谢!

【问题讨论】:

  • 你能提供一个可重现的例子吗?
  • 您提供的列new 包含您的预期输出?如果是这样,我很难理解你想要什么。
  • @Jimbou new 是我想要的输出。我只是编了个例子。事实上,我正在尝试为 300 万条记录执行此操作,因此我无法手动执行此操作
  • @raistlin 你能解释一下你的问题吗?澄清一下,我想要代码生成new 函数的想法。让我进一步解释一下,对于患者 #1,即使他没有被诊断出第一种疾病,但在那次访问前 20 天内,他在较早的事件中被诊断出对该疾病呈阳性,这就是为什么它是 TRUE
  • 已添加第二个解决方案。

标签: r loops dplyr


【解决方案1】:

1) 创建一个函数gen_new,它为每个患者填写缺失的日期编号,给出m。然后它使用rollapplyrany(..., na.rm = TRUE) 来查找尾随的20 个或更少的元素中的任何一个是否为TRUE,然后使用window 将结果子集返回到存在的日期。要将其应用于所有患者,请使用aveave 将强制 gen_new 产生的逻辑为 0/1,因此将其输出与 1 进行比较以转换回逻辑。

library(zoo)

n <- nrow(DF)

gen_new <- function(ix) with(DF[ix, ], {
  rng <- range(DaysToEvent)
  m <- merge(zoo(Dis1, DaysToEvent), zoo(, seq(rng[1], rng[2])))
  window(rollapplyr(m, 20, any, na.rm = TRUE, partial = TRUE), DaysToEvent)
})

DF <- transform(DF, new2 = ave(1:n, Patient, FUN = gen_new) == 1)

# check that new and new2 are the same
identical(DF$new, DF$new2)
## [1] TRUE

2) 这个避免了 (1) 中的合并,因此可能更快。它定义了一个函数Any,它接受一个逻辑动物园对象,并确定在结束的 20 内是否有任何 TRUE 元素。然后它将gen_new 定义为rollapplyr 它针对一个人。最后,它使用ave 将其应用于每个人。

library(zoo)

n <- nrow(DF)

Any <- function(x) any(x[time(x) > end(x) - 20], na.rm = TRUE)

gen_new <- function(ix) with(DF[ix, ], {
  z <- zoo(Dis1, DaysToEvent)
  rollapplyr(z, 20, Any, coredata = FALSE, partial = TRUE)
})

DF <- transform(DF, new2 = ave(1:n, Patient, FUN = gen_new) == 1)

# check that new and new2 are the same
identical(DF$new, DF$new2)
## [1] TRUE

注意:输入数据DF的可复现形式为:

Lines <- "Patient DaysToEvent  Dis1  Dis2  Dis3   new
      1         130  TRUE FALSE FALSE  TRUE
      1         135 FALSE FALSE FALSE  TRUE
      2         456  TRUE  TRUE FALSE  TRUE
      2         500 FALSE FALSE FALSE  FALSE
      2         550  TRUE FALSE FALSE  TRUE
      2         560 FALSE  TRUE  TRUE  TRUE
      3         200 FALSE FALSE FALSE  FALSE
      3         400  TRUE  TRUE FALSE  TRUE
      3         410 FALSE  TRUE FALSE  TRUE
      3         510 FALSE FALSE FALSE  FALSE
      4           1  TRUE FALSE FALSE  TRUE
      4          20 FALSE  TRUE FALSE  TRUE
      4         110 FALSE FALSE FALSE  FALSE"
DF <- read.table(text = Lines, header = TRUE)

【讨论】:

  • 感谢您的建议。我在您的评论中了解了动物园功能,这非常有趣。但是,有一种更简单的方法可以做到这一点,我曾经想出过一次,但现在却陷入了困境。你的方法虽然有效,但运行时间很长,我将在没有超级计算机的情况下对 300 万次观测执行此过程
【解决方案2】:

我愿意接受更有效的建议,但这里是仅使用 dplyr 的解决方案:

library(tidyr)
library(dplyr)

group_by(mydata,Patient) %>% 
    do(new = sapply(.$DaysToEvent,function(x)
        {
            any(.$Dis1*between(.$DaysToEvent,x-20,x))
        }
    ) %>% 
    unnest()

【讨论】:

  • 当我在答案中的注释中的 DF 上运行它时,它会失败并出现错误。
  • @G.Grothendieck 很有趣。是哪个错误?并确保您加载库 tidyr 。如果你觉得这个姿势有帮助,请给一个积极的投票。我正在努力建立如此“声誉”
  • 开始一个新的R会话,将代码复制并粘贴到我的答案末尾的注释中,输入mydata &lt;- DF这一行,然后复制并粘贴您的代码,您将看到错误。
  • 我按照您的指示,没有任何问题
  • 我在 R 3.4.0 补丁 (Windows) 上使用 dplyr_0.7.1 和 tidyr_0.6.3。我得到的错误信息是:Error in mutate_impl(.data, dots) : Column new must be length 1 (the group size), not 2
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-12-15
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
  • 2013-07-21
  • 2021-08-16
相关资源
最近更新 更多