【问题标题】:Ruby: Working with Arrays & Loops - The Simple Moving AverageRuby:使用数组和循环——简单的移动平均线
【发布时间】:2015-01-12 04:40:13
【问题描述】:

在 ruby​​ 中使用简单的移动平均线,并提出了这段代码,特别是三天移动平均线:

 a = [3, 3, 3, 3, 5, 9, 7, 8, 9, 11]
 sma = []

 for i in 2 ... 9 do
   sma.push((a[i] + a[i-1] + a[i-2])/3.0)
 end

这段代码通过了,看起来很简单,但是,如果数组包含数百个项目怎么办?我如何为 50 天的平均值添加 50 项?是否有不同的方法或者是否应该在代码中嵌套另一个循环?

*另外,我知道这种类型的操作有很多宝石,但我更感兴趣的是从头开始创建它。

【问题讨论】:

  • 我很高兴您发现我的回答很有帮助,但以后请考虑在调用绿色复选标记之前稍等片刻。 (我建议至少花几个小时。)SO 的许多新手选择发布的第一个适合他们的答案。不幸的是,这可能会阻碍其他可能更好的答案,也可能会使仍在研究答案的成员短路。

标签: ruby arrays loops


【解决方案1】:

Enumerable#each_cons 方法非常适合这种计算:

def moving_average(a, ndays, precision)
  a.each_cons(ndays).map { |e| e.reduce(&:+).fdiv(ndays).round(precision) }
end
a = [3, 4, 1, 2, 5, 9, 7, 8, 9, 11]

moving_average(a,3,2)
  #=> [2.67, 2.33, 2.67, 5.33, 7.0, 8.0, 8.0, 9.33] 

对于这个例子,

enum = a.each_cons(3) 
  #=> #<Enumerator: [3, 4, 1, 2, 5, 9, 7, 8, 9, 11]:each_cons(3)> 

枚举器enum传入块中的值可以通过将enum转换为数组得到:

enum.to_a 
  #=> [[3, 4, 1], [4, 1, 2], [1, 2, 5], [2, 5, 9],
  #    [5, 9, 7], [9, 7, 8], [7, 8, 9], [8, 9, 11]]

map 然后将这些元素中的每一个转换为平均值。


如果andays很大,可以通过如下方式实现更高的效率。

def moving_average(a,ndays,precision)
  (0..a.size-ndays-1).each_with_object([a[0,ndays].sum]) do |i,arr|
    arr << arr.last - a[i] + a[i+ndays]
  end.map { |tot| tot.fdiv(ndays).round(precision) }
end

moving_average(a,3,2)
  #=> [2.67, 2.33, 2.67, 5.33, 7.0, 8.0, 8.0, 9.33] 

合计后

tot1 = [3, 4, 1].sum
  #=> 8

计算第一个 3 天移动平均线所需的,计算第二个 3 天移动平均线所需的 [4, 1, 2] 的总数计算如下:

tot2 = tot1 + 2 - 3
  #=> 7

其中2[4, 1, 2] 的最后一个元素,3[3, 4, 1] 的第一个元素。

虽然此示例没有节省时间,但可以看出,当 andays 很大时,计算前一个总数将节省时间,因为计算复杂度从 O(n^2) 降低到 @ 987654342@,其中n = a.size

【讨论】:

  • 谢谢,成功了。这个方法我不知道,另记一个!
  • 虽然这是一个不错的技巧,但请注意,除非您将数组 lookback-1 向右移动,否则它不是有效的移动平均线。 [3,3,3] 的 SMA 不应该是 [3,3,3.6](由上面的代码提供),而是 [nil,nil,3]
  • @DannyB,代码生成moving_average([3,3,3],3,2) #=&gt; [3.0] 。请注意,对于任何数组,arrarr.each_cons(n) 返回一个枚举器,它将生成 arr.size-n+1 大小为 n 的数组。由于移动平均线从第一个 ndays 元素开始,我认为没有理由使用 nil 占位符。
  • 如果您没有看到 nil 占位符的原因,我猜您没有尝试在图表上绘制这两个。在我使用过的几乎所有现实世界的应用程序中,您生成的任何滚动序列都必须是源的并行数组,因此您可以将它们绘制在一起。不要误会我的意思,它是一个很好的答案,它快速高效,但在我的情况下,它必须被lookback-1 抵消。
猜你喜欢
  • 2011-03-07
  • 1970-01-01
  • 1970-01-01
  • 2013-04-15
  • 1970-01-01
  • 2022-01-26
  • 2012-10-04
  • 2015-01-29
  • 2017-09-01
相关资源
最近更新 更多