Tengo un marco de datos:
df1 = pd.DataFrame( [['2011-01-01','2011-01-03','A'], ['2011-04-01','2011-04-01','A'], ['2012-08-28','2012-08-30','B'], ['2015-04-03','2015-04-05','A'], ['2015-08-21','2015-08-21','B']], columns=['d0', 'd1', 'event']) d0 d1 event 0 2011-01-01 2011-01-03 A 1 2011-04-01 2011-04-01 A 2 2012-08-28 2012-08-30 B 3 2015-04-03 2015-04-05 A 4 2015-08-21 2015-08-21 BContiene algunos eventos A y B que ocurrieron en el intervalo especificado de d0 a d1. (En realidad hay más eventos, están mezclados, pero no tienen intersección por fechas). Además, este intervalo puede ser de 1 día (d0 = d1). Necesito pasar de df1 a df2 en el que estos intervalos de tiempo se "desenrollan" para cada evento, es decir:
df2 = pd.DataFrame( [['2011-01-01','A'], ['2011-01-02','A'], ['2011-01-03','A'], ['2011-04-01','A'], ['2012-08-28','B'], ['2012-08-29','B'], ['2012-08-30','B'], ['2015-04-03','A'], ['2015-04-04','A'], ['2015-04-05','A'], ['2015-08-21','B']], columns=['Date', 'event']) Date event 0 2011-01-01 A 1 2011-01-02 A 2 2011-01-03 A 3 2011-04-01 A 4 2012-08-28 B 5 2012-08-29 B 6 2012-08-30 B 7 2015-04-03 A 8 2015-04-04 A 9 2015-04-05 A 10 2015-08-21 BIntenté hacer esto basándome en el remuestreo y comparando áreas donde ffill = bfill pero no pude encontrar nada. ¿Cómo se puede hacer esto de la manera más sencilla?
No sé si esta es la "más simple", pero es la forma más intuitiva que se me ocurre para hacerlo. Itero sobre las filas y lo desenrollo manualmente en un nuevo marco de datos. Esto significa que observo cada fila, repaso las fechas entre d0 y d1 , y construyo una fila para cada una de ellas y las compilo en un marco de datos:
from datetime import timedelta def unroll_events(df): rows = [] for _, row in df.iterrows(): event = row['event'] start = row['d0'] end = row['d1'] current = start while current != end: rows.append(dict(Date=current, event=event)) current += timedelta(days=1) rows.append(dict(Date=current, event=event)) # make sure last one is included return pd.DataFrame(rows)Podemos set_index en el event , luego crear un rango de date_range por fila, luego explode para desenredar los rangos y reset_index para crear el marco de datos:
df2 = ( df1.set_index('event') .apply(lambda r: pd.date_range(r['d0'], r['d1']), axis=1) .explode() .reset_index(name='Date')[['Date', 'event']] ) df2 :
Date event 0 2011-01-01 A 1 2011-01-02 A 2 2011-01-03 A 3 2011-04-01 A 4 2012-08-28 B 5 2012-08-29 B 6 2012-08-30 B 7 2015-04-03 A 8 2015-04-04 A 9 2015-04-05 A 10 2015-08-21 BProbemos la comprensión para crear los pares de fecha y evento.
pd.DataFrame(((d, c) for (*v, c) in df1.to_numpy() for d in pd.date_range(*v)), columns=['Date', 'Event']) Date Event 0 2011-01-01 A 1 2011-01-02 A 2 2011-01-03 A 3 2011-04-01 A 4 2012-08-28 B 5 2012-08-29 B 6 2012-08-30 B 7 2015-04-03 A 8 2015-04-04 A 9 2015-04-05 A 10 2015-08-21 B