seleccionar panda index filas fila eliminar drop columnas python pandas

python - index - pandas drop



Eliminar filas con índices duplicados(Pandas DataFrame y TimeSeries) (4)

Estoy leyendo algunos datos meteorológicos automáticos de la web. Las observaciones ocurren cada 5 minutos y se compilan en archivos mensuales para cada estación meteorológica. Una vez que termine de analizar un archivo, el DataFrame se ve más o menos así:

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

El problema que tengo es que a veces un científico retrocede y corrige las observaciones, no editando las filas erróneas, sino agregando una fila duplicada al final de un archivo. Un ejemplo simple de tal caso se ilustra a continuación:

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'') data = {''A'' : range(6), ''B'' : range(6)} data1 = {''A'' : [20, -30, 40], ''B'' : [-50, 60, -70]} df1 = pandas.DataFrame(data=data, index=index) df2 = pandas.DataFrame(data=data1, index=index[:3]) df3 = df1.append(df2) 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

Y entonces necesito df3 para convertirse evenutally:

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

Pensé que agregar una columna de números de fila ( df3[''rownum''] = range(df3.shape[0]) ) me ayudaría a seleccionar la fila inferior para cualquier valor de DatetimeIndex , pero estoy atascado en calcular fuera de las group_by o pivot (o ???) para que funcione.


Tenga en cuenta que hay una mejor respuesta (a continuación) basada en los últimos pandas

Esta debería ser la respuesta aceptada.

Mi respuesta original, que ahora está desactualizada, se conserva como referencia.

Una solución simple es usar drop_duplicates

df4 = df3.drop_duplicates(subset=''rownum'', keep=''last'')

Para mí, esto funcionó rápidamente en grandes conjuntos de datos.

Esto requiere que ''rownum'' sea la columna con duplicados. En el ejemplo modificado, ''rownum'' no tiene duplicados, por lo tanto, nada se elimina. Lo que realmente queremos es tener los ''cols'' en el índice. No he encontrado una manera de decirle a drop_duplicates que solo considere el índice.

Aquí hay una solución que agrega el índice como una columna de marco de datos, descarta los duplicados y luego elimina la nueva columna:

df3 = df3.reset_index().drop_duplicates(subset=''index'', keep=''last'').set_index(''index'')

Y si quiere que las cosas vuelvan a estar en el orden correcto, simplemente llame a sort en el marco de datos.

df3 = df3.sort()


Lamentablemente, no creo que Pandas le permita a uno abandonar los dúplex de los índices. Sugeriría lo siguiente:

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!


Oh mi. ¡Esto es realmente tan simple!

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

Edición de seguimiento 2013-10-29 En el caso en que tengo un MultiIndex bastante complejo, creo que prefiero el enfoque groupby . Aquí hay un ejemplo simple para la posteridad:

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

y aquí está la parte importante

# 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


Sugeriría usar el método duplicado en el índice de Pandas:

df3 = df3[~df3.index.duplicated(keep=''first'')]

Mientras que todos los demás métodos funcionan, la respuesta actualmente aceptada es de lejos la menos efectiva para el ejemplo proporcionado. Además, aunque el método groupby es solo un poco menos eficiente , creo que el método duplicado es más legible.

Usando los datos de muestra proporcionados:

>>> %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

Tenga en cuenta que puede conservar el último elemento cambiando el argumento de mantener.

También se debe tener en cuenta que este método también funciona con MultiIndex (usando df1 como se especifica en el ejemplo de Paul ):

>>> %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