【问题标题】:Replace Loop with vectorised operation用矢量化操作替换循环
【发布时间】:2016-06-01 12:39:11
【问题描述】:

我正在使用这个code 在情节中创建烛台。但是,它包含一个效率非常低的循环(循环 10K 观察需要 38 秒)。它还使用rbind 函数,这意味着必须将日期转换为数字然后再返回,考虑到它是一个带时间的日期,这似乎并不直接。

我试图用更高效的函数替换的循环是:

for(i in 1:nrow(prices)){
x <- prices[i, ]

# For high / low
mat <- rbind(c(x[1], x[3]), 
             c(x[1], x[4]),
             c(NA, NA))

plot.base <- rbind(plot.base, mat)
}

输出是一个向量,第一个观察值是输入数据的第一个(日期)和第三列,第二个观察值是输入数据的第一个和第四列,第三个观察值是两个 NA。 NA 在以后的绘图中很重要。

实现这一目标的最有效方法是什么?

最小可重现示例:

library(quantmod)

  prices <- getSymbols("MSFT", auto.assign = F)

  # Convert to dataframe
  prices <- data.frame(time = index(prices),
                       open = as.numeric(prices[,1]),
                       high = as.numeric(prices[,2]),
                       low = as.numeric(prices[,3]),
                       close = as.numeric(prices[,4]),
                       volume = as.numeric(prices[,5]))

 # Create line segments for high and low prices
  plot.base <- data.frame()

    for(i in 1:nrow(prices)){
x <- prices[i, ]

# For high / low
mat <- rbind(c(x[1], x[3]), 
             c(x[1], x[4]),
             c(NA, NA))

plot.base <- rbind(plot.base, mat)
}

编辑:

dput(head(prices))
structure(list(time = structure(c(13516, 13517, 13518, 13521, 
13522, 13523), class = "Date"), open = c(29.91, 29.700001, 29.629999, 
29.65, 30, 29.799999), high = c(30.25, 29.969999, 29.75, 30.1, 
30.18, 29.889999), low = c(29.4, 29.440001, 29.450001, 29.530001, 
29.73, 29.43), close = c(29.860001, 29.809999, 29.639999, 29.93, 
29.959999, 29.66), volume = c(76935100, 45774500, 44607200, 50220200, 
44636600, 55017400)), .Names = c("time", "open", "high", "low", 
"close", "volume"), row.names = c(NA, 6L), class = "data.frame")

【问题讨论】:

  • 代码正在增长一个对象 (plot.base)。这大约是您在编程中可以做的最慢的操作。请提供a minimal reproducible example 以方便替代方案的开发和测试。
  • @Roland 完整示例在链接中。我将在原始帖子中包含一个最小的示例
  • 示例应该在你的问题正文中
  • @Roland,记录完成!
  • 对不起,我不会安装一个包只是为了重新创建一个stackoverflow的例子。只需提供dput(head(prices)) 的输出并显示相应的预期输出即可。

标签: r


【解决方案1】:

我会警惕在循环中增长对象的教程。这是您在编程中可以做的最慢的操作之一。 (这就像购买一个书架,其空间正好适合您的书籍,然后每次购买新书时都要更换书架。)

像这样使用子集:

res <- data.frame(date = rep(prices[, 1], each = 3),
                  y = c(t(prices[,c(3:4)])[c(1:2, NA),])) #transpose, subset, make to vector
res[c(FALSE, FALSE, TRUE), 1] <- NA
#         date     y
#1  2007-01-03 30.25
#2  2007-01-03 29.40
#3        <NA>  <NA>
#4  2007-01-04 29.97
#5  2007-01-04 29.44
#6        <NA>  <NA>
#7  2007-01-05 29.75
#8  2007-01-05 29.45
#9        <NA>  <NA>
#10 2007-01-08 30.10
#11 2007-01-08 29.53
#12       <NA>  <NA>
#13 2007-01-09 30.18
#14 2007-01-09 29.73
#15       <NA>  <NA>
#16 2007-01-10 29.89
#17 2007-01-10 29.43
#18       <NA>  <NA>

【讨论】:

  • 关于 10K 观察:原始循环 30.54 秒。这个方法是 0.013 秒。
猜你喜欢
  • 1970-01-01
  • 2020-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-24
相关资源
最近更新 更多