Ich lese einige automatisierte Wetterdaten aus dem Internet. Die Beobachtungen erfolgen alle 5 Minuten und werden für jede Wetterstation in monatlichen Dateien zusammengestellt. Sobald ich eine Datei analysiert habe, sieht der DataFrame ungefähr so aus:
Sta Precip1hr Precip5min Temp DewPnt WindSpd WindDir AtmPress
Date
2001-01-01 00:00:00 KPDX 0 0 4 3 0 0 30.31
2001-01-01 00:05:00 KPDX 0 0 4 3 0 0 30.30
2001-01-01 00:10:00 KPDX 0 0 4 3 4 80 30.30
2001-01-01 00:15:00 KPDX 0 0 3 2 5 90 30.30
2001-01-01 00:20:00 KPDX 0 0 3 2 10 110 30.28
Das Problem, das ich habe, ist, dass ein Wissenschaftler manchmal zurückgeht und Beobachtungen korrigiert - nicht indem er die fehlerhaften Zeilen bearbeitet, sondern indem er eine doppelte Zeile an das Ende einer Datei anfügt. Ein einfaches Beispiel für einen solchen Fall ist unten dargestellt:
import pandas
import datetime
startdate = datetime.datetime(2001, 1, 1, 0, 0)
enddate = datetime.datetime(2001, 1, 1, 5, 0)
index = pandas.DatetimeIndex(start=startdate, end=enddate, freq='H')
data1 = {'A' : range(6), 'B' : range(6)}
data2 = {'A' : [20, -30, 40], 'B' : [-50, 60, -70]}
df1 = pandas.DataFrame(data=data1, index=index)
df2 = pandas.DataFrame(data=data2, index=index[:3])
df3 = df2.append(df1)
df3
A B
2001-01-01 00:00:00 20 -50
2001-01-01 01:00:00 -30 60
2001-01-01 02:00:00 40 -70
2001-01-01 03:00:00 3 3
2001-01-01 04:00:00 4 4
2001-01-01 05:00:00 5 5
2001-01-01 00:00:00 0 0
2001-01-01 01:00:00 1 1
2001-01-01 02:00:00 2 2
Und so muss ich df3
gleich werden:
A B
2001-01-01 00:00:00 0 0
2001-01-01 01:00:00 1 1
2001-01-01 02:00:00 2 2
2001-01-01 03:00:00 3 3
2001-01-01 04:00:00 4 4
2001-01-01 05:00:00 5 5
Ich dachte , dass eine Spalte mit Zeilennummern hinzugefügt ( df3['rownum'] = range(df3.shape[0])
) würde mir helfen , die unterste Zeile für jeden Wert der Auswahl aus DatetimeIndex
, aber ich bin fest auf die herauszufinden , group_by
oder pivot
(oder ???) Anweisungen , um diese Arbeit zu machen.
Antworten:
Ich würde vorschlagen, die duplizierte Methode im Pandas-Index selbst zu verwenden:
Während alle anderen Methoden funktionieren, ist die derzeit akzeptierte Antwort für das angegebene Beispiel bei weitem die am wenigsten leistungsfähige. Während die Groupby-Methode nur geringfügig weniger performant ist, finde ich die duplizierte Methode besser lesbar.
Verwendung der bereitgestellten Beispieldaten:
Beachten Sie, dass Sie das letzte Element behalten können, indem Sie das Argument keep ändern.
Es sollte auch beachtet werden, dass diese Methode auch funktioniert
MultiIndex
(unter Verwendung von df1, wie in Pauls Beispiel angegeben ):quelle
loc
möglicherweise nicht notwendig. Tun Sie dies einfachdf3 = df3[~df3.index.duplicated(keep='first')]
, wodurch alle Zeilen mit doppeltem Index bis auf das erste Vorkommen gelöscht werden.Eine einfache Lösung ist zu verwenden
drop_duplicates
Für mich funktionierte dies schnell bei großen Datenmengen.
Dies erfordert, dass 'rownum' die Spalte mit Duplikaten ist. In dem modifizierten Beispiel hat 'rownum' keine Duplikate, daher wird nichts eliminiert. Was wir wirklich wollen, ist, dass die 'cols' auf den Index gesetzt werden. Ich habe keine Möglichkeit gefunden, drop_duplicates anzuweisen, nur den Index zu berücksichtigen.
Hier ist eine Lösung, die den Index als Datenrahmenspalte hinzufügt, Duplikate darauf löscht und dann die neue Spalte entfernt:
Und wenn Sie die Dinge wieder in der richtigen Reihenfolge haben möchten, rufen Sie einfach
sort
den Datenrahmen auf.quelle
df.reset_index().drop_duplicates(cols='index',take_last=True).set_index('index')
reset_index()
die Spalten level_0, level_1 usw. hinzugefügt. Wenn Ihr Index einen Namen hat, wird dieser Name anstelle der Bezeichnung "index" verwendet. Das macht dies zu etwas mehr als einem Einzeiler, um es für jeden DataFrame richtig zu machen.index_label = getattr(df.index, 'names', getattr(df.index, 'name', 'index'))
danncols=index_label
dannset_index(index_labels)
und auch das ist nicht kinderleicht (funktioniert nicht für unbenannte Multiindizes).idx = df.index.name or 'index'
, man könnte auch tundf2 = df.reset_index(); df2.drop_duplicates(idx, inplace=True); df2.set_index(idx, inplace=True)
, um die Zwischenkopien (aufgrund derinplace=True
) zu vermeidenOh mein. Das ist eigentlich so einfach!
Follow-up-Bearbeitung 29.10.2013 Wenn ich einen ziemlich komplexen Ansatz
MultiIndex
habe, bevorzuge ich dengroupby
Ansatz. Hier ist ein einfaches Beispiel für die Nachwelt:und hier ist der wichtige Teil
quelle
level=[0,1]
funktioniert dies andernfalls (wenn ein Name None ist), wenn es zwei Ebenen gibtdf1.groupby(level=[0,1]).last()
. Dies sollte ein Teil von Pandas sein, als Ergänzung zudrop_duplicates
df.index.names
ist nur eine einfache Möglichkeit, nach allen Ebenen des Index zu gruppieren.xarray
für den Umgang mit doppelten DateTime-Indizes funktioniert, bei denen makeds.resample
undds.groupby
Operationen fehlschlagenxarray
so lange , wie Sie die Änderunggrouped = df3.groupby(level=0)
zugrouped = df3.groupby(dim='time')
oder was auch immer die Dimension ist , dass enthält DuplikateLeider glaube ich nicht, dass Pandas es einem erlaubt, Dups von den Indizes zu streichen. Ich würde folgendes vorschlagen:
quelle
Wenn jemand wie ich eine verkettbare Datenmanipulation mit der Pandas-Punktnotation (wie Piping) mag, kann Folgendes nützlich sein:
Dies ermöglicht die Verkettung von Anweisungen wie folgt:
quelle
TypeError: 'Series' objects are mutable, thus they cannot be hashed
Hat das tatsächlich bei Ihnen funktioniert?Duplikate entfernen (Keeping First)
Duplikate entfernen (Keeping Last)
Tests: 10k-Schleifen unter Verwendung der OP-Daten
quelle