Ruby Array группа и среднее значение по часам - PullRequest
0 голосов
/ 04 декабря 2009

Мы получаем наши данные от датчика, который записывает и хранит данные в виде хэшей. В любое время он измеряет несколько таких вещей:

{: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 секунд), и нам необходимо удалить некоторые данные. В идеале мы хотели бы экспортировать 1 такт в час за последние 24 часа, поэтому у нас есть что-то вроде

{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 часа, я бы хотел экстраполировать их на среднее значение между предыдущим и следующим часом. Кто-нибудь может помочь?

Ответы [ 3 ]

3 голосов
/ 04 декабря 2009

Более функциональная версия (с простой интерполяцией пропущенных значений)

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)}

Надеюсь, что это работает

2 голосов
/ 04 декабря 2009

как то так

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
0 голосов
/ 04 декабря 2009

Если вы не интересуетесь историей, а только приблизительным значением фактических значений, рассмотрите возможность использования «движущейся метрики» (http://en.wikipedia.org/wiki/Moving_average).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...