Estoy leyendo algunos datos meteorológicos automatizados 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 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 regresa y corrige las observaciones, no editando las filas erróneas, sino agregando una fila duplicada al final de un archivo. A continuación se ilustra un ejemplo simple de tal caso:
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
Y, entonces, necesito df3
convertirme en realidad:
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 la DatetimeIndex
, pero estoy atascado en averiguar las declaraciones group_by
o pivot
(o ???) para que funcione.
Respuestas:
Sugeriría usar el método duplicado en el Índice Pandas:
Si bien todos los demás métodos funcionan, la respuesta actualmente aceptada es, con mucho, la menos eficaz para el ejemplo proporcionado. Además, si bien el método groupby es solo un poco menos eficaz , creo que el método duplicado es más legible.
Usando los datos de muestra proporcionados:
Tenga en cuenta que puede conservar el último elemento cambiando el argumento de mantenimiento.
También se debe tener en cuenta que este método también funciona
MultiIndex
(usando df1 como se especifica en el ejemplo de Paul ):fuente
loc
Puede que no sea necesario. Simplemente hazlodf3 = df3[~df3.index.duplicated(keep='first')]
, lo que eliminará todas las filas con índice duplicado excepto la primera aparición.Una solución simple es usar
drop_duplicates
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 que los 'cols' se establezcan 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, coloca duplicados en eso y luego elimina la nueva columna:
Y si desea que las cosas vuelvan a estar en el orden correcto, solo llame
sort
al marco de datos.fuente
df.reset_index().drop_duplicates(cols='index',take_last=True).set_index('index')
reset_index()
agrega columnas level_0, level_1, etc. Y si su índice tiene un nombre, ese nombre se usará en lugar de la etiqueta "index". Eso hace que esto sea un poco más que una línea para hacerlo bien para cualquier DataFrame.index_label = getattr(df.index, 'names', getattr(df.index, 'name', 'index'))
entoncescols=index_label
,set_index(index_labels)
e incluso esto no es infalible (no funcionará para múltiples índices sin nombre).idx = df.index.name or 'index'
, uno también podría hacerdf2 = df.reset_index(); df2.drop_duplicates(idx, inplace=True); df2.set_index(idx, inplace=True)
para evitar las copias intermedias (debido a lainplace=True
)Oh mi. ¡Esto es realmente tan simple!
Edición de seguimiento 29/10/2013 En el caso de que tenga bastante complejo
MultiIndex
, creo que prefiero elgroupby
enfoque. Aquí hay un ejemplo simple para la posteridad:y aquí está la parte importante
fuente
level=[0,1]
que funcionará si hay 2 nivelesdf1.groupby(level=[0,1]).last()
. Esto debería ser parte de Pandas como un complemento paradrop_duplicates
df.index.names
es solo una forma fácil de agrupar por todos los niveles del índice.xarray
para tratar con índices de fechads.resample
yds.groupby
xarray
el tiempo que cambia elgrouped = df3.groupby(level=0)
quegrouped = df3.groupby(dim='time')
o lo que es la dimensión que contiene duplicadosDesafortunadamente, no creo que Pandas permita que uno baje duplicados de los índices. Sugeriría lo siguiente:
fuente
Si a alguien como yo le gusta la manipulación de datos encadenables utilizando la notación de puntos pandas (como las tuberías), entonces lo siguiente puede ser útil:
Esto permite encadenar declaraciones como esta:
fuente
TypeError: 'Series' objects are mutable, thus they cannot be hashed
¿Esto realmente funcionó para usted?Eliminar duplicados (Mantener primero)
Eliminar duplicados (Mantener último)
Pruebas: 10k bucles utilizando los datos de OP
fuente