【问题标题】:Ruby Array group and average by hourRuby Array 组和按小时平均
【发布时间】:2009-12-04 10:19:28
【问题描述】:

我们从记录和存储哈希等数据的传感器获取数据。 在任何时候它都会测量一些类似的东西:

{:temperature => 30, :pression => 100, :recorded_at => 14:34:23}
{:temperature => 30, :pression => 101, :recorded_at => 14:34:53}
{:temperature => 31, :pression => 102, :recorded_at => 14:34:24}
{:temperature => 30, :pression => 101, :recorded_at => 14:34:55}
{:temperature => 30, :pression => 102, :recorded_at => 14:34:25}
{:temperature => 31, :pression => 101, :recorded_at => 14:34:56}

我们需要能够以 JSON 格式导出该数据,但我们有太多数据(传感器大约每 30 秒记录一次),我们需要删除一些数据。理想情况下,我们希望在过去 24 小时内每小时导出 1 个测量值,所以我们有类似

{0 => {:temperature => 30, :pression => 100}, 1 => {:temperature => 30, :pression => 100}, 2 => {:temperature => 30, :pression => 100}, 3 => {:temperature => 30, :pression => 100}, 4 => {:temperature => 30, :pression => 100}}

每小时的温度是该小时内测得的所有温度的平均值。 此外,如果出于某种原因,某些数据在 1 小时内丢失,我想通过作为前一小时和下一小时之间的平均值来推断它。有人可以帮忙吗?

【问题讨论】:

    标签: ruby arrays structure hash


    【解决方案1】:

    更多功能版本(缺失值的简单插值)

    probs = [{:temperature => .. }] # array of measurings
    
    def average(list, key)
      list.reduce(0){|acc,el| acc+el[key]} / list.length unless list.empty
    end
    
    prob_groups = probs.group_by{|prob| prob[:recorded_at][0,2].to_i}
    average_groups = prob_groups.map do |hour,prob_group|
      { hour => {
          :temperature => average(prob_group, :temperature),
          :pression    => average(prob_group, :pression)
      }}
    end.reduce{|acc,el| acc.merge(el)}
    
    def interpolate(p, n, key)
      (p[key] + n[key])/2 unless p.nil? || n.nil? || p[key].nil? || n[key].nil?
    end
    
    resuls = (1..24).map do |hour|
      if average_groups[hour]
        { hour => average_groups[hour] }
      else
        { hour => {
          :temperature => interpolate(average_groups[hour-1], average_groups[hour+1], :temperature),
          :pression => interpolate(average_groups[hour-1], average_groups[hour+1], :pression)
        }}
      end
    end.reduce{|acc,el| acc.merge(el)}
    

    希望有效果

    【讨论】:

    • 请注意,在 1.8.7 中引入了 Enumerable#reduce 作为 #inject 的新首选别名(我不知道,所以其他人可能也不知道)
    【解决方案2】:

    类似的东西

    t = [....] - array of measurings
    result = {}
    
    (1..24).each do|hour| 
        #  measurings of given hour
        measurings = t.select{|measuring| measuring[:recorded_at][0, 2].to_i == hour}
    
        #  average temperature of hour
        sum = measurings.inject(0){|sum, measuring| sum + measuring[:temperature].to_i} 
        average_temperature = (measurings.length == 0)? nil: sum/measurings.length.to_f
    
        result[hour] = average_temperature
    end
    

    【讨论】:

      【解决方案3】:

      如果您对历史感兴趣,而只对实际值的近似值感兴趣,请考虑使用“移动指标”(http://en.wikipedia.org/wiki/Moving_average)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-10-17
        • 2015-07-31
        • 2011-12-10
        • 1970-01-01
        • 2012-05-06
        • 1970-01-01
        相关资源
        最近更新 更多