2016-08-28 1 views
1

Ich bin neu bei Python und ich hoffe, dass mir jemand mit diesem Leistungsproblem helfen kann. Meine Daten wie folgt aussieht:Wie gruppiere ich einen Datenrahmen mit Informationen über zwei Zeilen?

    TIMESTAMP A 
34 2050-09-08 03:00:00 EST 3.0 
40 2050-09-08 07:00:00 EST 3.0 
67 2050-09-08 17:00:00 EST 6.0 
84 2050-09-08 23:00:00 EST 6.0 
89 2050-09-09 01:00:00 EST 11.0 
103 2050-09-09 07:00:00 EST 10.0 
110 2050-09-09 11:00:00 EST 10.0 
118 2050-09-09 15:00:00 EST 10.0 

möchte ich die Zeitintervalle erhalten, in denen die Werte in Spalte A sind Stetig (S), Erhöhung (I) oder fallend (D).

In diesem Moment verwende ich eine For-Schleife, um die Zeilen zu vergleichen und die Steigung zwischen diesen Werten zu berechnen. Solange sich das Vorzeichen der Steigung nicht für jede Iteration ändert, wird der Endzeitstempel des Intervalls aktualisiert. Dies führt zu Intervallen wie Intervall (Anfang, Ende, Status). Das Ergebnis für das obige Beispiel wäre:

Interval(2050-09-08 03:00:00 EST, 2050-09-08 07:00:00 EST, S) 
Interval(2050-09-08 07:00:00 EST, 2050-09-08 17:00:00 EST, I) 
Interval(2050-09-08 17:00:00 EST, 2050-09-08 23:00:00 EST, S) 
etc. 

Da der Datensatz viele Zeilen und Spalten enthält, Ich versuche, einen Weg zu finden, diese effizienter zu kodieren (ohne for-Schleife).

data['slope'] = compute_slopes(data) 
data['state'].apply(lambda x: get_state(x)) 
data["shift"] = data["state"].shift(1) 
data["check"] = data["state"] != data["shift"] 
data["group"] = data["check"].cumsum() 
begin_group = data.groupby("group").first() 
end_group = data.groupby("group").last() 
result = pd.concat([begin_group, end_group]) 
result = result.sort_values('TIMESTAMP') 

       def compute_slopes(data): 
        next_df = data.shift(-1) 
        return getSlope(pd.to_datetime(df['TIMESTAMP'], format = '%Y-%m-%d %H:%M:%S EST'), df['A'], pd.to_datetime(next_df['TIMESTAMP'], format = '%Y-%m-%d %H:%M:%S EST'), next_df['A']) 


       def get_slope(x1, y1, x2, y2): 
        return (y2 - y1)/((x2 - x1).dt.total_seconds()/60) 


       def get_state(slope): 
        if(slope < 0): 
         state = 'D'  #DECREASING 
        elif(slope == 0): 
         state = 'S'  #STEADY 
        else: 
         state = 'I'  #INCREASING 

        return state 

Der obige Code führt zu so etwas wie unten, aber diese Datenrahmen Gruppierung funktioniert nicht, da es ein Zustand, der gehört 03.00.00 und 07.00.00 zu zwei Zeitstempel (Zustand S gehört, ist).

 TIMESTAMP     A  slope  state 
34 2050-09-08 03:00:00 EST 3.0 0.000000  S 
40 2050-09-08 07:00:00 EST 3.0 0.005000  I 
67 2050-09-08 17:00:00 EST 6.0 0.000000  S 
84 2050-09-08 23:00:00 EST 6.0 0.041667  I 
89 2050-09-09 01:00:00 EST 11.0 -0.002778  D 
103 2050-09-09 07:00:00 EST 10.0 0.000000  S 
110 2050-09-09 11:00:00 EST 10.0 0.000000  S 
118 2050-09-09 15:00:00 EST 10.0 0.000000  S 

In gewisser Weise, ich will diese Zustände zu gruppieren und den Anfangs- und End-Zeitstempel für jeden Zustand erhalten und es in einem Intervall speichern. Kennt jemand einen schnelleren Weg als nur das Durchlaufen des Datenrahmens?

Antwort

0

Dies sollte hilfreich sein. Verwenden Sie viele shift und verwenden Sie dann groupby + agg.

df.loc[df.A < df.A.shift(-1), 'State'] = 'I' 
df.loc[df.A > df.A.shift(-1), 'State'] = 'D' 
df.loc[df.A == df.A.shift(-1).ffill(), 'State'] = 'S' 
df['StateGroup'] = (df.State != df.State.shift()).cumsum() 
df['NextTIMESTAMP'] = df.TIMESTAMP.shift(-1).ffill() 
df 

enter image description here

aggs = dict(A=['mean', 'count', 'first', 'last'], State=['first'], 
      TIMESTAMP={'Start': 'first'}, NextTIMESTAMP={'End': 'last'}) 
df.groupby('StateGroup').agg(aggs) 

enter image description here

+0

Dies ist auf jeden Fall hilfreich, genau das, was ich suchte. Danke vielmals! – MarkM

+1

Ich habe eine drei für eine spezielle: df ['State'] = np.where (df.A. pct_change()> 0, "I", np.where (df.A. pct_change() <0, " D "," S ")) – Merlin

Verwandte Themen