2016-10-24 11 views
3

Ich habe einen Panda-Datenrahmen, die wie folgt aussieht:Kombinieren Datenrahmen Reihen auf Bedingungen

INPUT - hier am Beispiel runnable Code zu erstellen, um die INPUT: bis

#Create Dataframe with example data 
df_example = pd.DataFrame(columns=["START_D","ID_1", "ID_2", "STOP_D"]) 
df_example["START_D"] = ['2014-06-16', '2014-06-01', '2016-05-01','2014-05-28', '2014-05-20', '2015-09-01'] 
df_example['ID_1'] = [1,2,3,2,1,1] 
df_example['ID_2'] = ['a', 'a', 'b', 'b', 'a', 'a'] 
df_example["STOP_D"] = ['2014-07-28', '2014-07-01', '2016-06-01', '2014-08-01', '2014-07-29', '2015-10-01'] 

#Convert to datetime 
df_example["START_D"] = pd.to_datetime(df_example["START_D"]) 
df_example["STOP_D"] = pd.to_datetime(df_example["STOP_D"]) 
df_example 

START_D ID_1 ID_2  STOP_D 
0 2014-06-16  1 a 2014-07-28 
1 2014-06-01  2 a 2014-07-01 
2 2016-05-01  3 b 2016-06-01 
3 2014-05-28  2 b 2014-08-01 
4 2014-05-20  1 a 2014-07-29 
5 2015-09-01  1 a 2015-10-01 

und ich bin auf der Suche nach einem Weg, Gruppieren Sie nach ID_1 und führen Sie die Zeilen zusammen, an denen sich START_D und STOP_D überlappen. Die start_d wird die kleinste und die stop_d die größte. Unten sehen Sie die gewünschte Ausgabe, die ich über alle Zeilen (Iterrows) durchlaufen und ein Element zur Zeit überprüfen kann.

OUTPUT Auch wenn dieser Ansatz funktioniert, denke ich, dass es langsam ist (für große DF) und ich denke, dass es einen Python-Pandas Weg geben muss, um das zu tun.

>>> df_result 
    START_D ID_1  STOP_D 
    0 2014-05-20  1 2014-07-29 
    1 2014-05-28  2 2014-08-01 
    2 2016-05-01  3 2016-06-01 
    3 2015-09-01  1 2015-10-01 

danke!

+1

Bitte überprüfen [Wie gut reproduzierbare Pandas Beispiele machen] (http://stackoverflow.com/questions/20109391/how-to-make-good-reproducible-pandas-examples) – jezrael

Antwort

1
  • sort_values
  • groupby('ID_1')
  • Spur STOP_D.cummax() und sehen, ob START_D kleiner als vor cummax
  • cumsum Gruppierungen zu erzeugen
  • aggminSTART_D und maxSTOP_D
zu packen
df_example = df.sort_values(['START_D', 'STOP_D']) 

def collapse(df): 
    s, e = 'START_D', 'STOP_D' 
    grps = df[s].gt(df[e].cummax().shift()).cumsum() 
    funcs = {s: 'min', e: 'max', 'ID_1': 'first'} 
    return df.groupby(grps).agg(funcs) 

df_example.groupby('ID_1').apply(collapse).reset_index(drop=True) 

enter image description here

0

Die Schwierigkeit in Ihrem Problem besteht darin, dass die Aggregation zu einem einzelnen Eintrag führen muss. Wenn also START_D und STOP_D nicht überlappend sind, aber die ID1 identisch ist, funktioniert keine Aggregation (auch keine benutzerdefinierte). Ich empfehle die folgenden Schritte:

  1. Durchlaufen Sie jede ID und stellen Sie sicher, dass die gewünschte Überlappung immer auftritt. Dies kann mit etwas witziger Codierung vektorisiert werden. Wenn ein Konflikt gefunden wird, generieren Sie eine neue ID (mit einer neuen Spalte wie ID3), um den Konflikt zu lösen. Ansonsten setzen Sie ID1 einfach in ID3, wenn kein Konflikt besteht.
  2. Führen Sie eine groupby ID3 (oder was auch immer Sie wählten es zu nennen)

    df_result = df_example.groupby(['ID1']).agg({START_D: min, STOP_D: max}) 
    

Der Schlüssel zur Leistungssteigerung mit einer vektorisiert Lösung Überprüfung für Start- und Stopp-Konflikt kommen. Viel Glück! Hoffe das hilft!

Verwandte Themen