【问题标题】:Producing a more efficient for loop产生更有效的 for 循环
【发布时间】:2017-11-12 21:24:56
【问题描述】:

我创建了一个函数,该函数将 Cox 回归模型应用于测试数据,基于协变量创建生存函数,然后预测每个测试观察的当前时间 30 天后的生存概率。

下面的示例使用了肺数据集并且效果很好。但是,应用于我自己的数据处理时间很繁琐。对于 n = 60000,我只是在一小时后停止了它,因为它不适合我打算使用该程序的目的。

看看代码结构,有没有明显的方法可以加快速度?

require(dplyr, survival, pec)

cox_model <- coxph(Surv(time, status) ~ sex, data = lung)

surv_preds <- function(model, query) {

  prediction <- vector(mode = "numeric", length = nrow(query))
  time <- 30

  for(i in 1:nrow(query)) {
    prediction[i] <- predictSurvProb(model, newdata = query[i, ], times = query[i, "time"] + time)
  }
  prediction
}

surv_preds(cox_model, lung)

【问题讨论】:

  • 您还应该将您的帖子标记为[r]
  • 完成。谢谢。
  • 您从哪里获得lung 数据?
  • 生存包

标签: r performance for-loop


【解决方案1】:

除了问题中的包之外,另一种方法是purrrlyr 中的by_row 函数。

library(purrrlyr)

prediction <- lung %>%
  mutate(time = time + 30) %>%
  by_row(~predictSurvProb(cox_model, newdata = ., times = .$time)) %>%
  .$.out %>%
  unlist

在产生相同结果的同时,它更整洁,但是,microbenchmark 的早期运行并没有显示出处理时间的改进。

微基准

# Unit: seconds
#                        expr      min       lq    mean   median       uq      max neval
# surv_preds(cox_model, lung) 1.531631 1.561518 1.59431 1.574664 1.591117 2.157002   100
# (purrrlyr)                  1.841713 1.887438 1.921371 1.90474 1.92649  2.170205   100

这将使两种解决方案在我正在使用的硬件上运行超过 24 小时。 鉴于此答案似乎不再能解决您的问题,而且我不熟悉并行处理选项,我很乐意将其删除,除非有人发现将其保留在这里的价值。

【讨论】:

  • 感谢您的意见。我似乎找不到解决方案。 purrrly 的例子很好,但不幸的是对于我的预期目的来说仍然太慢了。如果一切顺利,这可能是我唯一的选择。
【解决方案2】:

解决了!!如果有兴趣,我想发布我使用的解决方案。我设法完全消除了对 for 循环的需求。

predictSurvProb(cox_model, 
                newdata = lung, 
                times = lung[ , "time"] + 30)[1, ]

这给了我我需要的输出。关键是我从结果矩阵中索引第一行及其所有列。此代码使用每个观察的唯一生存函数估计来预测从观察在曲线上的当前位置算起 30 天的生存概率。

@thc 的回答最终实际上为我指明了正确的方向。

【讨论】:

    【解决方案3】:

    您无需一次预测一行。您可以一次完成所有操作。例如:

    cox_model <- coxph(Surv(time, status) ~ sex, data = lung)
    
    surv_preds <- function(model, query) {
    
      prediction <- vector(mode = "numeric", length = nrow(query))
      time <- 30
    
      for(i in 1:nrow(query)) {
        prediction[i] <- predictSurvProb(model, newdata = query[i, ], times = query[i, "time"] + time)
      }
      prediction
    }
    
    surv_preds2 <- function(model, query) {
    
    time <- 30
    
    prediction <- predictSurvProb(model, newdata = query, times = query[, "time"] + time)
      prediction
    }
    
    
    microbenchmark(surv_preds(cox_model, lung), surv_preds2(cox_model, lung), times=5)
    

    结果:

    Unit: milliseconds
                             expr       min         lq      mean     median         uq        max neval cld
      surv_preds(cox_model, lung) 1017.5587 1031.58422 1056.7026 1062.30476 1072.33865 1099.72672     5   b
     surv_preds2(cox_model, lung)   30.3567   30.78582   35.7851   31.81206   33.00534   52.96559     5  a 
    

    【讨论】:

    • 这其实不是我需要的。这段代码传递了一个时间向量来预测,但我只需要将一个时间传递给每个测试实例,即它的时间 + 30 天。
    • 你可以做同样的事情。只需更改查询,使每一行都是一个每个测试实例。
    • 我不明白你的意思。你能在我给出的代码示例中实现它吗?
    • 是的,不过虽然是做冗余计算,但还是要快很多。我更新了上面的代码并提供了证明的基准。可以通过时间排序提取出你想要的向量。
    • @thc,我可能遗漏了一些东西,但两个函数的结果不相等。 surv_preds2[1, ] == surv_preds2[2, ]surv_preds != surv_preds2[1, ],即使在排序之后
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-15
    • 2018-05-08
    • 1970-01-01
    • 2017-02-07
    • 2012-07-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多