python - seleccionar - recorrer data frame pandas
¿Cómo unir dos marcos de datos para los que los valores de columna están dentro de un cierto rango? (5)
Dados dos marcos de datos
df_1
y
df_2
, cómo unirlos de modo que la columna de fecha y hora
df_1
encuentre entre el
start
y el
end
marco de datos
df_2
:
print df_1
timestamp A B
0 2016-05-14 10:54:33 0.020228 0.026572
1 2016-05-14 10:54:34 0.057780 0.175499
2 2016-05-14 10:54:35 0.098808 0.620986
3 2016-05-14 10:54:36 0.158789 1.014819
4 2016-05-14 10:54:39 0.038129 2.384590
print df_2
start end event
0 2016-05-14 10:54:31 2016-05-14 10:54:33 E1
1 2016-05-14 10:54:34 2016-05-14 10:54:37 E2
2 2016-05-14 10:54:38 2016-05-14 10:54:42 E3
Obtenga el
event
correspondiente donde
df1.timestamp
está entre
df_2.start
y
df2.end
timestamp A B event
0 2016-05-14 10:54:33 0.020228 0.026572 E1
1 2016-05-14 10:54:34 0.057780 0.175499 E2
2 2016-05-14 10:54:35 0.098808 0.620986 E2
3 2016-05-14 10:54:36 0.158789 1.014819 E2
4 2016-05-14 10:54:39 0.038129 2.384590 E3
En este método, asumimos que se usan objetos TimeStamp.
df2 start end event
0 2016-05-14 10:54:31 2016-05-14 10:54:33 E1
1 2016-05-14 10:54:34 2016-05-14 10:54:37 E2
2 2016-05-14 10:54:38 2016-05-14 10:54:42 E3
event_num = len(df2.event)
def get_event(t):
event_idx = ((t >= df2.start) & (t <= df2.end)).dot(np.arange(event_num))
return df2.event[event_idx]
df1["event"] = df1.timestamp.transform(get_event)
Explicación de
get_event
Para cada marca de tiempo en
df1
, diga
t0 = 2016-05-14 10:54:33
,
(t0 >= df2.start) & (t0 <= df2.end)
contendrá 1 verdadero.
(Ver ejemplo 1).
Luego, tome un producto punto con
np.arange(event_num)
para obtener el índice del evento al que pertenece
t0
.
Ejemplos:
Ejemplo 1
t0 >= df2.start t0 <= df2.end After & np.arange(3)
0 True True -> T 0 event_idx
1 False True -> F 1 -> 0
2 False True -> F 2
Tome
t2 = 2016-05-14 10:54:35
para otro ejemplo
t2 >= df2.start t2 <= df2.end After & np.arange(3)
0 True False -> F 0 event_idx
1 True True -> T 1 -> 1
2 False True -> F 2
Finalmente usamos
transform
para transformar cada marca de tiempo en un evento.
Opción 1
idx = pd.IntervalIndex.from_arrays(df_2[''start''], df_2[''end''], closed=''both'')
df_2.index=idx
df_1[''event'']=df_2.loc[df_1.timestamp,''event''].values
opcion 2
df_2[''timestamp'']=df_2[''end'']
pd.merge_asof(df_1,df_2[[''timestamp'',''event'']],on=''timestamp'',direction =''forward'',allow_exact_matches =True)
Out[405]:
timestamp A B event
0 2016-05-14 10:54:33 0.020228 0.026572 E1
1 2016-05-14 10:54:34 0.057780 0.175499 E2
2 2016-05-14 10:54:35 0.098808 0.620986 E2
3 2016-05-14 10:54:36 0.158789 1.014819 E2
4 2016-05-14 10:54:39 0.038129 2.384590 E3
Puedes usar el módulo pandasql
import pandasql as ps
sqlcode = ''''''
select df_1.timestamp
,df_1.A
,df_1.B
,df_2.event
from df_1
inner join df_2
on d1.timestamp between df_2.start and df2.end
''''''
newdf = ps.sqldf(sqlcode,locals())
Una solución simple es crear un
interval index
desde el
start and end
configuración
closed = both
luego usar
get_loc
para obtener el evento, es decir (Espero que todas las horas estén en dtype de fecha y hora)
df_2.index = pd.IntervalIndex.from_arrays(df_2[''start''],df_2[''end''],closed=''both'')
df_1[''event''] = df_1[''timestamp''].apply(lambda x : df_2.iloc[df_2.index.get_loc(x)][''event''])
Salida:
timestamp A B event 0 2016-05-14 10:54:33 0.020228 0.026572 E1 1 2016-05-14 10:54:34 0.057780 0.175499 E2 2 2016-05-14 10:54:35 0.098808 0.620986 E2 3 2016-05-14 10:54:36 0.158789 1.014819 E2 4 2016-05-14 10:54:39 0.038129 2.384590 E3
idx = pd.IntervalIndex.from_arrays(df_2[''start''], df_2[''end''], closed=''both'')
event = df_2.loc[idx.get_indexer(df_1.timestamp), ''event'']
event
0 E1
1 E2
1 E2
1 E2
2 E3
Name: event, dtype: object
df_1[''event''] = event.values
df_1
timestamp A B event
0 2016-05-14 10:54:33 0.020228 0.026572 E1
1 2016-05-14 10:54:34 0.057780 0.175499 E2
2 2016-05-14 10:54:35 0.098808 0.620986 E2
3 2016-05-14 10:54:36 0.158789 1.014819 E2
4 2016-05-14 10:54:39 0.038129 2.384590 E3
Referencia:
una pregunta sobre
IntervalIndex.get_indexer.