Алгоритм суммирования / суммирования значений из графика временного ряда, где точки данных не совпадают по времени - PullRequest
4 голосов
/ 21 декабря 2010

У меня проблема с графикой / анализом, которую я не могу понять.Я могу сделать грубую силу, но она слишком медленная, может, у кого-то есть идея получше, или кто-то знает, или есть быстрая библиотека для python?агрегировать (и впоследствии строить).Проблема в том, что значения x по всей серии не совпадают, и я действительно не хочу прибегать к дублированию значений в временные интервалы.

Итак, учитывая эти 2 серии:

S1: (1;100) (5;100) (10;100)
S2: (4;150) (5;100) (18;150)

При сложении вместе должно получиться:

ST: (1;100) (4;250) (5;200) (10;200) (18;250)

Логика:

x=1 s1=100, s2=None, sum=100
x=4 s1=100, s2=150, sum=250 (note s1 value from previous value)
x=5 s1=100, s2=100, sum=200
x=10 s1=100, s2=100, sum=200
x=18 s1=100, s2=150, sum=250

В настоящее время я думаю, что нужно перебрать отсортированный список ключей (x), сохранить предыдущийзначение для каждой серии, и запросить каждый набор, если у него есть новый y для x.

Любые идеи будут оценены!

Ответы [ 3 ]

1 голос
/ 21 декабря 2010

Один из возможных подходов:

  1. Форматировать все элементы серии в кортежи (x, y, идентификатор серии), например, (4, 150, 1), добавить их в список кортежей и отсортировать по возрастанию.

  2. Объявите список с длиной, равной количеству серий, чтобы сохранить значение «последний раз видел» для каждой серии.

  3. Итерация по каждому кортежу элементов списка на шаге (1) и:

    3.1 Обновить список «последних посещений» в соответствии с идентификатором серии в кортеже

    3.2 Если x предыдущего итерированного кортежа не совпадает с x текущего кортежа, суммируйте все элементы списка «последних увиденных» и добавьте результат в окончательный список.

Теперь с моим грязным тестом:

>>> 
S1 = ((1, 100), (5, 100), (10, 100))
S2 = ((4, 150), (5, 100), (18, 150))
>>> all = []
>>> for s in S1: all.append((s[0], s[1], 0))
...
>>> for s in S2: all.appned((s[0], s[1], 1))
...
>>> all
[(1, 100, 0), (5, 100, 0), (10, 100, 0), (4, 150, 1), (5, 100, 1), (18, 150, 1)]
>>> all.sort()
>>> all
[(1, 100, 0), (4, 150, 1), (5, 100, 0), (5, 100, 1), (10, 100, 0), (18, 150, 1)]
>>> last_val = [0]*2
>>> last_x = all[0][0]
>>> final = []
>>> for e in all:
...     if e[0] != last_x:
...             final.append((last_x, sum(last_val)))
...     last_val[e[2]] = e[1]
...     last_x = e[0]
...
>>> final.append((last_x, sum(last_val)))
>>> final
[(1, 100), (4, 250), (5, 200), (10, 200), (18, 250)]
>>>
1 голос
/ 21 декабря 2010

Вот еще один способ сделать это, добавив больше поведения к отдельным потокам данных:

class DataStream(object):
    def __init__(self, iterable):
        self.iterable = iter(iterable)
        self.next_item = (None, 0)
        self.next_x = None
        self.current_y = 0
        self.next()

    def next(self):
        if self.next_item is None:
            raise StopIteration()
        self.current_y = self.next_item[1]
        try:
            self.next_item = self.iterable.next()
            self.next_x = self.next_item[0]
        except StopIteration:
            self.next_item = None
            self.next_x = None
        return self.next_item

    def __iter__(self):
        return self


class MergedDataStream(object):
    def __init__(self, *iterables):
        self.streams = [DataStream(i) for i in iterables]
        self.outseq = []

    def next(self):
        xs = [stream.next_x for stream in self.streams if stream.next_x is not None]
        if not xs:
            raise StopIteration()
        next_x = min(xs)
        current_y = 0
        for stream in self.streams:
            if stream.next_x == next_x:
                stream.next()
            current_y += stream.current_y
        self.outseq.append((next_x, current_y))
        return self.outseq[-1]

    def __iter__(self):
        return self


if __name__ == '__main__':
    seqs = [
        [(1, 100), (5, 100), (10, 100)],
        [(4, 150), (5, 100), (18, 150)],
        ]

    sm = MergedDataStream(*seqs)
    for x, y in sm:
        print "%02s: %s" % (x, y)

    print sm.outseq
1 голос
/ 21 декабря 2010

Примерно так:

def join_series(s1, s2):
    S1 = iter(s1)
    S2 = iter(s2)
    value1 = 0
    value2 = 0
    time1, next1 = next(S1)
    time2, next2 = next(S2)
    end1 = False
    end2 = False

    while True:    
        time = min(time1, time2)
        if time == time1:
            value1 = next1
            try:
                time1, next1 = next(S1)
            except StopIteration:
                end1 = True
                time1 = time2

        if time == time2:
            value2 = next2
            try:
                time2, next2 = next(S2)
            except StopIteration:
                end2 = True
                time2 = time1

        yield time, value1 + value2

        if end1 and end2:
            raise StopIteration

S1 = ((1, 100), (5, 100), (10, 100))
S2 = ((4, 150), (5, 100), (18, 150))

for result in join_series(S1, S2):
    print(result)

Он в основном сохраняет текущее значение S1 и S2 вместе с последующими из S1 и S2 и выполняет пошаговые действия на основе того, какое из них имеет наименьшее «предстоящее время». Должен обрабатывать списки различной длины и полностью использовать итераторы, чтобы иметь возможность обрабатывать массивные базы данных и т. Д. И т. П.

...