Completa los valores de NA en las series de pandas con una parada.

Estoy analizando una serie de tiempo y, en función de ciertos criterios, puedo seleccionar filas que son el inicio o el final de los eventos. En este punto, mi serie se parece a esto (dejé algunos valores repetitivos por brevedad):

La puesta en marcha

import numpy as np import pandas from pandas import Timestamp datadict = {'event': { Timestamp('2010-01-01 00:20:00', tz=None): 'event start', Timestamp('2010-01-01 00:30:00', tz=None): '--', Timestamp('2010-01-01 00:40:00', tz=None): '--', Timestamp('2010-01-01 00:50:00', tz=None): '--', Timestamp('2010-01-01 01:00:00', tz=None): '--', Timestamp('2010-01-01 01:10:00', tz=None): 'event end', Timestamp('2010-01-01 01:20:00', tz=None): '--', Timestamp('2010-01-01 02:20:00', tz=None): '--', Timestamp('2010-01-01 02:30:00', tz=None): 'event start', Timestamp('2010-01-01 02:40:00', tz=None): '--', Timestamp('2010-01-01 02:50:00', tz=None): '--', Timestamp('2010-01-01 03:00:00', tz=None): '--', Timestamp('2010-01-01 03:10:00', tz=None): '--', Timestamp('2010-01-01 03:20:00', tz=None): '--', Timestamp('2010-01-01 03:30:00', tz=None): 'event end', }} data = pandas.DataFrame.from_dict(datadict) event 2010-01-01 00:20:00 event start 2010-01-01 00:30:00 -- 2010-01-01 00:40:00 -- 2010-01-01 00:50:00 -- 2010-01-01 01:00:00 -- 2010-01-01 01:10:00 event end 2010-01-01 01:20:00 -- 2010-01-01 02:20:00 -- 2010-01-01 02:30:00 event start 2010-01-01 02:40:00 -- 2010-01-01 02:50:00 -- 2010-01-01 03:00:00 -- 2010-01-01 03:10:00 -- 2010-01-01 03:20:00 -- 2010-01-01 03:30:00 event end 

Esto es lo que me gustaría lograr ( idealmente sin bucles )

  event event number 2010-01-01 00:20:00 event start 1 2010-01-01 00:30:00 -- 1 2010-01-01 00:40:00 -- 1 2010-01-01 00:50:00 -- 1 2010-01-01 01:00:00 -- 1 2010-01-01 01:10:00 event end 1 2010-01-01 01:20:00 -- NA 2010-01-01 02:20:00 -- NA 2010-01-01 02:30:00 event start 2 2010-01-01 02:40:00 -- 2 2010-01-01 02:50:00 -- 2 2010-01-01 03:00:00 -- 2 2010-01-01 03:10:00 -- 2 2010-01-01 03:20:00 -- 2 2010-01-01 03:30:00 event end 2 2010-01-01 03:40:00 -- NA 2010-01-01 03:50:00 -- NA 

Esto es lo que he intentado

Con algunas suposiciones optimistas sobre la calidad de mis datos, puedo obtener Números de eventos como estos:

 table = data[data.event != '--'].reset_index() table['event number'] = 1 + np.floor(table.index / 2) table = table.set_index('index') event event number index 2010-01-01 00:20:00 event start 1 2010-01-01 01:10:00 event end 1 2010-01-01 02:30:00 event start 2 2010-01-01 03:30:00 event end 2 

Luego puedo join eso a mi dataframe original, y fillna con el method='ffill'

 data2 = data.join(table[['event number']]) data2['filled'] = data2['event number'].fillna(method='ffill') event event number filled 2010-01-01 00:20:00 event start 1 1 2010-01-01 00:30:00 -- NaN 1 2010-01-01 00:40:00 -- NaN 1 2010-01-01 00:50:00 -- NaN 1 2010-01-01 01:00:00 -- NaN 1 2010-01-01 01:10:00 event end 1 1 2010-01-01 01:20:00 -- NaN 1 # <- d'oh 2010-01-01 02:20:00 -- NaN 1 # <- d'oh 2010-01-01 02:30:00 event start 2 2 2010-01-01 02:40:00 -- NaN 2 2010-01-01 02:50:00 -- NaN 2 2010-01-01 03:00:00 -- NaN 2 2010-01-01 03:10:00 -- NaN 2 2010-01-01 03:20:00 -- NaN 2 2010-01-01 03:30:00 event end 2 2 

El problema

Como puede ver, el tiempo entre eventos (01:20 a 02:20) se está asociando con el evento # 1.

La pregunta

¿Hay alguna forma de saltar estas secciones sin hacer un bucle?

puede lograr esto con solo mirar la sum acumulada de número de event start de event start y número de event end de event end :

 >>> data['event number'] = (data.event == 'event start').cumsum() >>> data event event number 2010-01-01 00:20:00 event start 1 2010-01-01 00:30:00 -- 1 2010-01-01 00:40:00 -- 1 2010-01-01 00:50:00 -- 1 2010-01-01 01:00:00 -- 1 2010-01-01 01:10:00 event end 1 2010-01-01 01:20:00 -- 1 2010-01-01 02:20:00 -- 1 2010-01-01 02:30:00 event start 2 2010-01-01 02:40:00 -- 2 2010-01-01 02:50:00 -- 2 2010-01-01 03:00:00 -- 2 2010-01-01 03:10:00 -- 2 2010-01-01 03:20:00 -- 2 2010-01-01 03:30:00 event end 2 

ahora solo necesitas configurar nan cuando no hay evento; pero esos lugares corresponden a filas donde la sum acumulada del event start del event start es igual a la sum acumulada del event end del event end (con desplazamiento de 1 fila)

 >>> idx = data['event number'] == (data.event.shift(1) == 'event end').cumsum() >>> data.loc[idx, 'event number'] = np.nan >>> data event event number 2010-01-01 00:20:00 event start 1 2010-01-01 00:30:00 -- 1 2010-01-01 00:40:00 -- 1 2010-01-01 00:50:00 -- 1 2010-01-01 01:00:00 -- 1 2010-01-01 01:10:00 event end 1 2010-01-01 01:20:00 -- NaN 2010-01-01 02:20:00 -- NaN 2010-01-01 02:30:00 event start 2 2010-01-01 02:40:00 -- 2 2010-01-01 02:50:00 -- 2 2010-01-01 03:00:00 -- 2 2010-01-01 03:10:00 -- 2 2010-01-01 03:20:00 -- 2 2010-01-01 03:30:00 event end 2 [15 rows x 2 columns]