pandas.merge: coincide con la marca de tiempo más cercana> = la serie de marcas de tiempo

Tengo dos marcos de datos, los cuales contienen una columna de marca de tiempo de resolución de milisegundos y espaciada irregularmente. Mi objective aquí es hacer coincidir las filas de modo que para cada fila coincidente, 1) la primera marca de tiempo sea siempre más pequeña o igual que la segunda marca de tiempo, y 2) las marcas de tiempo coincidentes sean las más cercanas para todos los pares de marcas de tiempo que satisfacen 1).

¿Hay alguna manera de hacer esto con pandas.merge?

merge() no puede hacer este tipo de unión, pero puede usar searchsorted() :

Cree algunas marcas de tiempo aleatorias: t1 , t2 , hay en orden ascendente:

 import pandas as pd import numpy as np np.random.seed(0) base = np.array(["2013-01-01 00:00:00"], "datetime64[ns]") a = (np.random.rand(30)*1000000*1000).astype(np.int64)*1000000 t1 = base + a t1.sort() b = (np.random.rand(10)*1000000*1000).astype(np.int64)*1000000 t2 = base + b t2.sort() 

llame a searchsorted() para encontrar el índice en t1 para cada valor en t2 :

 idx = np.searchsorted(t1, t2) - 1 mask = idx >= 0 df = pd.DataFrame({"t1":t1[idx][mask], "t2":t2[mask]}) 

Aquí está la salida:

  t1 t2 0 2013-01-02 06:49:13.287000 2013-01-03 16:29:15.612000 1 2013-01-05 16:33:07.211000 2013-01-05 21:42:30.332000 2 2013-01-07 04:47:24.561000 2013-01-07 04:53:53.948000 3 2013-01-07 14:26:03.376000 2013-01-07 17:01:35.722000 4 2013-01-07 14:26:03.376000 2013-01-07 18:22:13.996000 5 2013-01-07 14:26:03.376000 2013-01-07 18:33:55.497000 6 2013-01-08 02:24:54.113000 2013-01-08 12:23:40.299000 7 2013-01-08 21:39:49.366000 2013-01-09 14:03:53.689000 8 2013-01-11 08:06:36.638000 2013-01-11 13:09:08.078000 

Para ver este resultado por gráfico:

 import pylab as pl pl.figure(figsize=(18, 4)) pl.vlines(pd.Series(t1), 0, 1, colors="g", lw=1) pl.vlines(df.t1, 0.3, 0.7, colors="r", lw=2) pl.vlines(df.t2, 0.3, 0.7, colors="b", lw=2) pl.margins(0.02) 

salida:

introduzca la descripción de la imagen aquí

Las líneas verdes son t1 , las líneas azules son t2 , las líneas rojas se seleccionan de t1 para cada t2 .

Aquí hay un método más simple y más general.

 # data and signal are want we want to merge keys = ['channel', 'timestamp'] # Could be simply ['timestamp'] index = data.loc[keys].set_index(keys).index # Make index from columns to merge on padded = signal.reindex(index, method='pad') # Key step -- reindex with filling joined = data.join(padded, on=keys) # Join to data if needed 

Los pandas ahora tienen la función merge_asof haciendo exactamente esto.

Utilicé una forma diferente a HYRY:

  1. haga una combinación regular con la combinación externa (how = ‘external’);
  2. ordenarlo por fecha
  3. use fillna (method = ‘pad’) para llenar solo las columnas que necesita y ‘pad’ si desea tomar la fila anterior;
  4. elimine todas las filas que no necesite de la combinación externa.

Todo esto se puede escribir en pocas líneas:

 df=pd.merge(df0, df1, on='Date', how='outer') df=df.sort(['Date'], ascending=[1]) headertofill=list(df1.columns.values) df[headertofill]=df[headertofill].fillna(method='pad') df=df[pd.isnull(df[var_from_df0_only])==False]