我有一个Ruby数组数组,它代表了一系列随时间记录的指标的观察结果。每个内部数组都有两个元素:
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月16日在06:00,12:00和23:00进行观察,它被分解为00:00-06:00,06:00-12:00,12: 00-23:00和23:00-00:00。
每个区间的值等于区间开始时的观察值,或者如果它是一天的开始则进行的最后一次观察。
例如,1月16日06:00-12:00间隔的值 200 ,因为在06:00记录的值为200.
1月15日00:00-06:00间隔的值 100 ,因为值100是在当天开始时记录的最后一次观察。
每个区间的加权值等于其值乘以它占用当天所有区间长度的分数。
例如,1月16日06:00-12:00区间的加权值 50 (200 * 0.25)。
每天的最终加权值是其间隔的加权值之和,强制为整数。
例如,1月16日的加权值为229,因为:
(100*(6/24) + 200*(6/24) + 300*(11/24) + 400*(1/24)).to_i = 229
数组中的第一个点是一个特殊情况:那天从那里开始,而不是在00:00,所以1月15日只有一个间隔:18:00-00:00,值为100,所以加权价值也是100。
有关如何开始解决这个问题的任何建议吗?
答案 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]
,其中dt
与23: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
。