30,000个数据点,在2周内发现最大的变化'时间

时间:2012-06-15 02:11:03

标签: algorithm

我有:

- 30,000 data points
- each data point is a measurement of type float
- each measurement is associated with a date
- each date has only one measurement
- no dates are without measurements
- the data comes in the form of a text file: 30,000 lines in this form:
    - YYYY-MM-DD I,F (e.g. 1977-02-08 20.74)
- measurement appearing in the source file are already sorted by date

我需要:

- a time-interval T with boundaries (s,e) /* start, end */
- (s - e = 14 days) the time-interval *must* be 2 weeks
- define min as the lowest value in the interval T
- define max as the greatest value in the interval T
- the chosen T needs to have the greatest distance btwn max and min of all possible Ts
- break ties among intervals T by choosing the most recent (with the greatest s value)
- the chosen T must consider all jumps in the 14 days, not just the values @ s and e
- if the overall "variance" in the interval is great but the jump 
  |max-min| is not the greatest in absolute value, T is not the right choice,
  even if it's an "exciting" interval

我在问:

- which algorithm to employ, considering algorithms are not my specialty
- which data structure to use to keep track of the subtotals

注意:

- an answer in pseudo code would be preferred, "prose" is fine if pressured for time
- an answer in Python would be... splendid :)

如果需要,您可以生成“虚拟”数据并将您提出的算法作为测试运行,或者我可以共享实际数据。

除了想知道最快的方法以便学习如何应用正确的解决方案和正确的算法之外,我并不关心这方面的表现。

我认为即使是最简单的迭代算法也能“证明”正确性,因为今天的计算机数据集很小。

到目前为止,我正在“遍历和携带14个测量的14个向量”,如果你能教会我如何用子总和逐步完成这个,那将非常感激。

2 个答案:

答案 0 :(得分:2)

滑动窗口确实在这里工作,通过保留两个堆栈(可能这有点误导,因为这可能最好实现为双端队列)。保留堆栈minstack和名为maxstack的堆栈。该算法的关键在于,minstack应该严格非递减,并且maxstack应该在幻灯片的所有点严格非增加。那么,我们该怎么做呢?

首先,将前14个点添加到堆栈中。我们将add(point)定义为:

为minstack执行此操作:

  • 虽然该点小于minstack的top元素,但删除minstack的top元素。
  • 将该点添加到minstack。

同样,对于maxstack:

  • 虽然新点大于maxstack的top元素,但删除maxstack的top元素。
  • 将该点添加到maxstack。

由于上面的属性,前14个元素的最小值和最大值应该是minstack和maxstack的底部元素。现在滑动窗口。我们只需要注意,如果左边的点在任何堆栈中仍然“活着”,那么它现在必然是最低点。因此,这应该很简单,只需:

slide():
    add(new_point)
    if (left_point == bottom(minstack)) remove_bottom(minstack)
    if (left_point == bottom(maxstack)) remove_bottom(maxstack)

这样做直到你的分数用完为止。您要查找的时间间隔是bottom(maxstack) - bottom(minstack)最大的时间间隔。

请注意,任何一点最多进入minstack / maxstack一次,并且每个点最多也会离开堆栈一次,因此无论所需间隔的大小如何,每个点最多只能执行4次操作。

编辑:我刚刚注意到你想在Python中实现一个实现。我真的不想解析数据,所以函数将值列表作为输入,并输出该数组中的索引(s,e):

import collections

def add(x, minstack, maxstack):
    while minstack and x < minstack[-1]: minstack.pop()
    while maxstack and x > maxstack[-1]: maxstack.pop()
    minstack.append(x)
    maxstack.append(x)

def get_largest_interval(points):
    minstack = collections.deque()
    maxstack = collections.deque()

    best_diff = -1
    best_interval = None

    for index, elem in enumerate(points):
        add(elem,minstack,maxstack)
        if index >= 14:
            if minstack[0] == points[index-14]: minstack.popleft()
            if maxstack[0] == points[index-14]: maxstack.popleft()

        if index >= 13:
            this_diff = maxstack[0]-minstack[0]
            if best_diff == -1 or this_diff >= best_diff:
                best_interval = (index-13, index)
                best_diff = this_diff

    return best_interval


print get_largest_interval([0, 2, 2,2,2,2,2,2,2,2,2,2,2,2,3])

答案 1 :(得分:1)

如果我了解你,你有:

30,000个不同的有序数据值。订购恰好按日期排序,但这不相关。

在这个集合中,有29,986个子集,其中的内容是一个有序序列,它从一个数据点开始,包含该初始点和13个数据点。


慢慢来:

1)将您的30,000个数据点读入一个大小为30,000的数组中。

2)分配一个29,986的数组。将此数组称为“潜在赢家”。
)3)通过扫描每个14点子集填充潜在赢家阵列,暂时保持子集中遇到的最大值和最小值。当这两个值在手中时,将(最大 - 最小)保存在潜在赢家内的起始点的索引位置。不要尝试任何滑动窗口优化;见下文。

4)对潜在赢家进行线性扫描,保存价值,并且(重要的)保存其所在的指数。

顺便说一下:如果没有单一的赢家,你会怎么做?如果所有数据点都具有相同的值,您将获得29,986个候选获胜者,所有人都具有相同的值。

5)优化:不分配和填补潜在的获胜者;将Current Winner初始化为元组(值,索引)为(0,-1)。如上所述计算每个14点子集的值,但在{Current Winner,“我从当前子集获得的值”中仅保留更好的值“}

6)滑动窗户:我没有想到这一点,但我认为保持滑动窗口比上述简单的线性通道更有效。

原因:好的,计算前14个点的值;获得最小值和最大值,并获得它们之间的间隔。但是等等,我们需要在下一个窗口中使用最小值和最大值。现在将窗口向上滑动一个位置。左端的价值消失了;但它是最小值,最大值还是介于两者之间?假设它是最小值,它现在已经消失了。什么值是第二低的分钟?我们没有这个信息。

为了保持滑动窗口,您需要对每个14数据点子序列进行排序,并记住所有值的索引位置。然后,当您滑动时,您可以知道左侧丢弃的值是否为旧值 min或old max,以及右边的新值是新的最小值还是新的最大值。但这不值得努力。

(这种情况提醒了一下Boyer-Moore快速子串查找算法。我不记得细节,但它涉及预处理整个输入并保留每个位置的表格价值出现。但这是偏离主题的方式)

希望这有助于......