我有一个由Ruby组成的数组数组,该数组表示对随时间记录的指标的一系列观察。每个内部数组都有两个元素:
Time
UTC中的一个实例,它描述观察记录的时间例如,我们可能会有类似的内容:
[
[<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。
每个时间间隔的值等于时间间隔开始时的观察值,如果等于一天的开始,则等于上一次进行的观察。
例如,由于在06:00记录的值为200,所以1月16日的06:00-12: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
关于如何开始解决这个问题的任何建议?
我假设没有日子没有条目。
我发现先转换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
time是相同的日期23:59:59
。[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
s的加权平均值(请注意,我们不使用的每个元素的第一个元素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
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句