Usuń wiersze pandy z zduplikowanymi indeksami
Jak usunąć wiersze o zduplikowanych wartościach indeksu?
W ramce danych pogodowych poniżej, czasami Naukowiec wraca i koryguje obserwacje-nie edytując błędnych wierszy, ale dodając zduplikowany wiersz na końcu pliku.
Czytam zautomatyzowane dane pogodowe z sieci (obserwacje odbywają się co 5 minut i są kompilowane do comiesięcznych plików dla każdej stacji pogodowej.) Po przetworzeniu pliku ramka Danych wygląda następująco:
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
Przykład przypadku duplikatu:
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
I tak potrzebuję df3
aby w końcu stać się:
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
Myślałem, że dodanie kolumny liczb wierszy (df3['rownum'] = range(df3.shape[0])
) pomoże mi wybrać najbardziej dolny wiersz dla dowolnej wartości DatetimeIndex
, ale utknąłem na wymyślaniu group_by
lub pivot
(lub ???) oświadczenia, aby to zadziałało.
7 answers
Sugerowałbym użycie metody duplikowanej na samym indeksie pand:
df3 = df3[~df3.index.duplicated(keep='first')]
Podczas gdy wszystkie inne metody działają, aktualnie akceptowana ODPOWIEDŹ jest zdecydowanie najmniej wydajna dla podanego przykładu. Ponadto, podczas gdy metoda groupby jest tylko nieco mniej wydajna, uważam, że zduplikowana metoda jest bardziej czytelna.
Na podstawie dostarczonych przykładowych danych:
>>> %timeit df3.reset_index().drop_duplicates(subset='index', keep='first').set_index('index')
1000 loops, best of 3: 1.54 ms per loop
>>> %timeit df3.groupby(df3.index).first()
1000 loops, best of 3: 580 µs per loop
>>> %timeit df3[~df3.index.duplicated(keep='first')]
1000 loops, best of 3: 307 µs per loop
Zauważ, że możesz zachować ostatni element zmieniając argument keep do 'last'
.
Należy również zauważyć, że ta metoda działa również z MultiIndex
(używając df1, jak podano w przykładzie Paula):
>>> %timeit df1.groupby(level=df1.index.names).last()
1000 loops, best of 3: 771 µs per loop
>>> %timeit df1[~df1.index.duplicated(keep='last')]
1000 loops, best of 3: 365 µs per loop
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-20 03:15:57
To dodaje indeks jako kolumnę ramki danych, upuszcza duplikaty na niej, a następnie usuwa nową kolumnę:
df = df.reset_index().drop_duplicates(subset='index', keep='last').set_index('index').sort_index()
Zauważ, że użycie .sort_index()
powyżej na końcu jest w razie potrzeby i jest opcjonalne.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-06 01:06:20
O mój Boże. To takie proste!
grouped = df3.groupby(level=0)
df4 = grouped.last()
df4
A B rownum
2001-01-01 00:00:00 0 0 6
2001-01-01 01:00:00 1 1 7
2001-01-01 02:00:00 2 2 8
2001-01-01 03:00:00 3 3 3
2001-01-01 04:00:00 4 4 4
2001-01-01 05:00:00 5 5 5
Kontynuacja edycji 2013-10-29
W przypadku, gdy mam dość złożony MultiIndex
, myślę, że wolę podejście groupby
. Oto prosty przykład dla potomności:
import numpy as np
import pandas
# fake index
idx = pandas.MultiIndex.from_tuples([('a', letter) for letter in list('abcde')])
# random data + naming the index levels
df1 = pandas.DataFrame(np.random.normal(size=(5,2)), index=idx, columns=['colA', 'colB'])
df1.index.names = ['iA', 'iB']
# artificially append some duplicate data
df1 = df1.append(df1.select(lambda idx: idx[1] in ['c', 'e']))
df1
# colA colB
#iA iB
#a a -1.297535 0.691787
# b -1.688411 0.404430
# c 0.275806 -0.078871
# d -0.509815 -0.220326
# e -0.066680 0.607233
# c 0.275806 -0.078871 # <--- dup 1
# e -0.066680 0.607233 # <--- dup 2
A oto ważna część
# group the data, using df1.index.names tells pandas to look at the entire index
groups = df1.groupby(level=df1.index.names)
groups.last() # or .first()
# colA colB
#iA iB
#a a -1.297535 0.691787
# b -1.688411 0.404430
# c 0.275806 -0.078871
# d -0.509815 -0.220326
# e -0.066680 0.607233
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-24 16:51:39
Niestety, nie sądzę, aby Pandy pozwalały zrzucić dups z indeksów. Proponuję:
df3 = df3.reset_index() # makes date column part of your data
df3.columns = ['timestamp','A','B','rownum'] # set names
df3 = df3.drop_duplicates('timestamp',take_last=True).set_index('timestamp') #done!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-28 05:17:36
Usuń duplikaty (zachowując najpierw)
idx = np.unique( df.index.values, return_index = True )[1]
df = df.iloc[idx]
Usuń duplikaty (zachowując ostatni)
df = df[::-1]
df = df.iloc[ np.unique( df.index.values, return_index = True )[1] ]
Testy: pętle 10K z wykorzystaniem danych OP
numpy method - 3.03 seconds
df.loc[~df.index.duplicated(keep='first')] - 4.43 seconds
df.groupby(df.index).first() - 21 seconds
reset_index() method - 29 seconds
Jeśli ktoś taki jak ja lubi manipulowanie danymi za pomocą notacji kropek pandy( np. Orurowanie), to może się przydać:
df3 = df3.query('~index.duplicated()')
Umożliwia to łączenie wyrażeń w następujący sposób:
df3.assign(C=2).query('~index.duplicated()').mean()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-26 11:05:46
Można zrzucić duplikaty indeksu za pomocą 'drop_duplikaty':
df.loc[df.index.drop_duplicates(keep='first')]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-17 14:12:17