将Ruby数组的时间序列值映射到加权间隔

时间:2014-10-04 06:47:18

标签: ruby arrays time

我有一个Ruby数组数组,它​​代表了一系列随时间记录的指标的观察结果。每个内部数组都有两个元素:

  • UTC中的Time实例,描述记录的时间
  • 观察的整数值

例如,我们可能会有:

[
  [<Time: 2014-01-15 @ 18:00>, 100],
  [<Time: 2014-01-16 @ 06:00>, 200],
  [<Time: 2014-01-16 @ 12:00>, 300],
  [<Time: 2014-01-16 @ 23:00>, 400],
  [<Time: 2014-01-17 @ 12:00>, 500],
  [<Time: 2014-01-18 @ 03:00>, 600],
  [<Time: 2014-01-18 @ 06:00>, 700],
]

目前的问题是将其转换为每个日期的加权值数组:

[
  [<Date: 2014-01-15>, 100],
  [<Date: 2014-01-16>, 229],
  ...
]

上述数组中每天的值可通过以下步骤获得:

  1. 将这一天划分为由每个观察和当天界限划分的一系列间隔。

      

    例如,自1月16日在06:00,12:00和23:00进行观察,它被分解为00:00-06:00,06:00-12:00,12: 00-23:00和23:00-00:00。

  2. 每个区间的值等于区间开始时的观察值,或者如果它是一天的开始则进行的最后一次观察。

      

    例如,1月16日06:00-12:00间隔的值 200 ,因为在06:00记录的值为200.

         

    1月15日00:00-06:00间隔的值 100 ,因为值100是在当天开始时记录的最后一次观察。

  3. 每个区间的加权值等于其值乘以它占用当天所有区间长度的分数。

      

    例如,1月16日06:00-12:00区间的加权值 50 (200 * 0.25)。

  4. 每天的最终加权值是其间隔的加权值之和,强制为整数。

      

    例如,1月16日的加权值为229,因为:

         

    (100*(6/24) + 200*(6/24) + 300*(11/24) + 400*(1/24)).to_i = 229

  5. 数组中的第一个点是一个特殊情况:那天从那里开始,而不是在00:00,所以1月15日只有一个间隔:18:00-00:00,值为100,所以加权价值也是100。

    有关如何开始解决这个问题的任何建议吗?

1 个答案:

答案 0 :(得分:2)

我认为没有没有参赛作品的日子。

我发现首先转换Time对象数组很方便。我用于转换的规则如下(arb指的是一个任意值,也可能等于val):

  • 第一天,将单个元素[dt, val]替换为三个元素:
    • [dt1, val],其中dt1的日期相同00:00:00
    • [dt2, arb],其中dt2的日期相同23:59:59
    • [dt3, val],其中dt3是一天后的00:00:00
  • 作为最后一天,如果[dt, val]是当天的最后一个元素,请添加元素[dt1, arb],其中dt23:59:59时的日期相同。< / LI>
  • 除了第一个和最后一个之外的每一天,如果[dt, val]是当天的最后一个元素,请添加两个元素:
    • [dt1, arb],其中dt1的日期相同23:59:59
    • [dt2, val],其中dt2是一天后的00:00:00

假设以下是您的初始数组。为清楚起见,我使用了字符串(允许我将"23:59:59"替换为"24:00"):

arr = [
  ["2014-01-15 18:00", 100],

  ["2014-01-16 06:00", 200],
  ["2014-01-16 12:00", 300],
  ["2014-01-16 23:00", 400],

  ["2014-01-17 12:00", 500],

  ["2014-01-18 03:00", 600],
  ["2014-01-18 06:00", 700]
]

在应用上述规则后,我们获得:

arr1 = [
  ["2014-01-15 00:00", 100],
  ["2014-01-15 24:00", 100],
  ["2014-01-16 00:00", 100],

  ["2014-01-16 06:00", 200],
  ["2014-01-16 12:00", 300],
  ["2014-01-16 23:00", 400],
  ["2014-01-16 24:00", 400],
  ["2014-01-17 00:00", 400],

  ["2014-01-17 12:00", 500],
  ["2014-01-17 24:00", 500],
  ["2014-01-18 00:00", 500],

  ["2014-01-18 03:00", 600],
  ["2014-01-18 06:00", 700],
  ["2014-01-18 24:00", 700]
]

或按日期分组的元素

arr1 = [
  ["2014-01-15 00:00", 100],
  ["2014-01-15 24:00", 100],

  ["2014-01-16 00:00", 100],
  ["2014-01-16 06:00", 200],
  ["2014-01-16 12:00", 300],
  ["2014-01-16 23:00", 400],
  ["2014-01-16 24:00", 400],

  ["2014-01-17 00:00", 400],
  ["2014-01-17 12:00", 500],
  ["2014-01-17 24:00", 500],

  ["2014-01-18 00:00", 500],
  ["2014-01-18 03:00", 600],
  ["2014-01-18 06:00", 700],
  ["2014-01-18 24:00", 700]
]

实施这些规则的代码应该是直截了当的。获得arr1后,使用Enumerable#chunk创建一个枚举器:

enum = arr1.chunk { |a| a.first[0,10] } 
  #=> #<Enumerator: #<Enumerator::Generator:0x000001010e30d8>:each>

让我们看看enum

的元素
enum.to_a
  #=> [["2014-01-15", [["2014-01-15 00:00", 100], ["2014-01-15 24:00", 100]]],
  #    ["2014-01-16", [["2014-01-16 00:00", 100], ["2014-01-16 06:00", 200],
  #      ["2014-01-16 12:00", 300], ["2014-01-16 23:00", 400],
  #      ["2014-01-16 24:00", 400]]],
  #    ["2014-01-17", [["2014-01-17 00:00", 400], ["2014-01-17 12:00", 500],
  #      ["2014-01-17 24:00", 500]]],
  #    ["2014-01-18", [["2014-01-18 00:00", 500], ["2014-01-18 03:00", 600],
  #      ["2014-01-18 06:00", 700], ["2014-01-18 24:00", 700]]]]

现在我们只需将每个元素(每个日期一个)映射到val的加权平均值(注意我们不使用enum的每个元素的第一个元素) :

enum.map { |_,arr| (arr.each_cons(2)
                       .reduce(0.0) { |t,((d1,v1),(d2,_))|
                          t + min_diff(d2,d1)*v1 }/1440.0).round(2) }
  #=> [100.0, 229.17, 450.0, 662.5]  

使用助手:

def min_diff(str1, str2)
  60*(str1[-5,2].to_i - str2[-5,2].to_i) + str1[-2,2].to_i - str2[-2,2].to_i 
end

把它们放在一起:

arr1.chunk { |a| a.first[0,10] }
    .map { |_,arr| (arr.each_cons(2)
                       .reduce(0.0) { |t,((d1,v1),(d2,_))| 
                          t + min_diff(d2,d1)*v1 }/1440.0).round(2) }
  #=> [100.0, 229.17, 450.0, 662.5]  

以及助手min_diff