【问题标题】:How to speed up the following function in R?如何加快R中的以下功能?
【发布时间】:2013-12-12 19:41:21
【问题描述】:

我有一个名为“marketdata”的数据框,其中包含 3,000,000 行(行名:1 到 3,000,000)和 2 列(列名:“mid”、“bo”)。

> head(marketdata)
    mid    bo  
1   250    0.05
2   251    0.07
3   252    0.13
4   249    0.08
5   250    0.12

我的功能如下:

movingWindow <- function (submarketdata) {
   temp <- submarketdata[submarketdata$bo <= 0.1, ]   
   return( c(mean(temp$mid), NROW(temp)/100) )
}

result <- lapply(c(101:NROW(marketdata)), function(i) movingWindow( marketdata[ (i-99):i , ] ))

例如,对于第 101 行,我将搜索 marketdata[2:101,]。然后找出那些“bo”值

但是,此脚本运行速度非常慢。完成所有 3,000,000 行大约需要 15 分钟。任何人都可以帮我加快速度吗?谢谢。

【问题讨论】:

  • 您需要提供marketdata的代表性样本。请阅读此FAQ
  • 嗯,你正在实现大约。每秒 3333 次输出。不需要您的 movingWindow 函数,因为它的每个输出都很容易矢量化。

标签: r optimization lapply


【解决方案1】:
set.seed(42)
marketdata <- data.frame(mid=runif(200, 245, 255),
                 bo=runif(200, 0, 0.2))

movingWindow <- function (submarketdata) {
  temp <- submarketdata[submarketdata$bo <= 0.1, ]   
  return( c(mean(temp$mid), NROW(temp)/100) )
}

result <- t(sapply(c(101:NROW(marketdata)), function(i) movingWindow( marketdata[ (i-99):i , ] )))

#faster alternative:
library(zoo)
r1 <- rollmean(marketdata$bo <= 0.1, 100)
all.equal(r1[-1], result[,2])

r2 <- rollsum((marketdata$bo <= 0.1)*marketdata$mid, 100)/(100*r1)

result2 <- cbind(r2, r1)

#same result?
all.equal(result, unname(result2[-1,]))
#[1] TRUE

#base R alternative (assuming there are no NA values in your data)
r1a <- na.omit(filter(marketdata$bo <= 0.1, rep(0.01, 100)))
r2a <- na.omit(filter((marketdata$bo <= 0.1)*marketdata$mid, rep(1, 100)))/(100*r1a)
result2a <- cbind(r2a, r1a)

#same result?
all.equal(result, unname(result2a[-1,]))
#[1] TRUE

备选方案多给出一个值(第一个值)。否则结果是相同的,并且两种选择都快得多。

示例的基准:

Unit: microseconds
        expr        min        lq    median        uq       max neval
    original  19006.144 19435.262 20824.245 21243.524 52965.168   100
alternative1   1444.574  1525.774  1607.264  1646.524  3486.940   100
alternative2    975.366  1006.913  1071.305  1106.437  3117.709   100

【讨论】:

  • 不应该你的 Alt#2 r2a 等式调用 r1a,而不是 r1 吗?
  • @CarlWitthoft 谢谢,我修好了。
  • 您好 Roland,非常感谢您的帖子。但是我觉得这种替代方法与我原来的方法产生了不同的结果。在我的函数中,我正在计算前 100 次更新中列“bo” 的前 100 个样本
  • 哦,我明白了。我确实犯了一个错误。平均值实际上是使用“rollsum”/(100*r1) 计算的,而不是返回有效样本数量的第一个 rollmean 函数。非常感谢。
猜你喜欢
  • 1970-01-01
  • 2016-02-22
  • 1970-01-01
  • 2020-06-22
  • 1970-01-01
  • 2022-01-06
  • 2022-10-06
  • 2015-12-05
  • 2011-10-12
相关资源
最近更新 更多