2010-12-21 13 views
4

Ich habe ein Graphik-/Analyseproblem, das mir nicht ganz klar ist. Ich kann eine rohe Gewalt anwenden, aber es ist zu langsam, vielleicht hat jemand eine bessere Idee oder weiß oder eine schnelle Bibliothek für Python?Algorithmus zum Summieren/Stapeln von Werten aus einem Zeitreihendiagramm, in dem Datenpunkte nicht pünktlich übereinstimmen

Ich habe 2+ Zeitreihendatensätze (x, y), die ich aggregieren (und anschließend plotten) möchte. Das Problem ist, dass die X-Werte in der Serie nicht übereinstimmen, und ich möchte wirklich nicht auf duplizierende Werte in Zeitbins zurückgreifen.

gegeben Also, diese 2-Serie:

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

Wenn aufaddiert, sollte in Folge:

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

Logic:

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 

Meine derzeitigen Überlegungen eine sortier iterieren ist Liste der Schlüssel (x), behalte den vorherigen Wert für jede Reihe und frage jeden Satz ab, wenn er ein neues y für das x hat.

Irgendwelche Ideen würden geschätzt werden!

+0

Ich habe Probleme, herauszufinden, Ihre Daten und wie ST: Ergebnisse von S1, S2. Bitte überprüfen Sie, wie S1, S2 in ST umgewandelt wird. Wenn Sie auch eine mehr pythonische Notation verwenden könnten, wie 'S1 = [(1, 100), (5, 100), (10, 100)]'. – kevpie

+0

Ich habe einige zusätzliche Sachen in der Post hinzugefügt ...total vergessen zu erwähnen, dass ich die Y-Werte summierte – Duncan

Antwort

1

Hier ist eine andere Art und Weise, es zu tun, mehr über das Verhalten auf der einzelnen Datenströme setzen:

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

Etwas wie folgt:

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) 

Es hält im Grunde genommen um den aktuellen Wert von S1 und S2 zusammen mit dem nächsten von S1 und S2, und die Schritte bis sie auf deren Basis die niedrigste „kommenden Zeit“ hat. Sollte behandeln Listen unterschiedlicher Länge und verwendet Iteratoren den ganzen Weg so sollte es in der Lage sein massiven Datenreihe zu handhaben, etc, etc.

1

Ein möglicher Ansatz:

  1. Format alle Serie Element in Tupel (x, y, Serien-ID), z (4, 150, 1) und fügen Sie sie zu einer Tupel-Liste hinzu und sortieren sie nach x aufsteigend.

  2. Deklarieren Sie eine Liste mit der Länge, die der Anzahl der Serien entspricht, um den Wert "Zuletzt gesehen" für jede Serie beizubehalten.

  3. Iterate durch jedes Element Tupel-Liste in Schritt (1), und:

    3.1 Aktualisieren der in Tupels "zuletzt" -Liste entsprechend Serie ID

    3.2 Wenn x von zuvor Doesn iteriert Tupels nicht mit x des aktuellen Tupels übereinstimmen, Summe aller Elemente der "Zuletzt gesehen" -Liste addieren und das Ergebnis zur endgültigen Liste hinzufügen.

Jetzt mit meinem schmutzigen Test:

>>> 
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)] 
>>>