Pandas.merge: соответствие ближайшей отметке времени >= серия временных меток

У меня есть два кадра данных, оба из которых содержат столбец временной метки с нерегулярным интервалом, миллисекунды. Моя цель состоит в том, чтобы сопоставить строки таким образом, чтобы для каждой строки соответствовала: 1) первая метка времени всегда меньше или равна второй временной отметке; 2) согласованные временные метки являются самыми близкими для всех пар временных меток, удовлетворяющих 1).

Есть ли способ сделать это с помощью pandas.merge?

Ответ 1

merge() не может выполнить такое соединение, но вы можете использовать searchsorted():

Создайте несколько случайных временных меток: t1, t2, есть в порядке возрастания:

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()

вызовите searchsorted(), чтобы найти индекс в t1 для каждого значения в t2:

idx = np.searchsorted(t1, t2) - 1
mask = idx >= 0

df = pd.DataFrame({"t1":t1[idx][mask], "t2":t2[mask]})

вот результат:

                         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

Чтобы просмотреть этот результат по графику:

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)

выход:

enter image description here

Зеленые линии t1, синие линии t2, красные линии выбраны из t1 для каждого t2.

Ответ 2

Вот более простой и более общий метод.

# 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

Ответ 3

У Pandas теперь есть функция merge_asof, делающая именно то, что было описано в принятом ответе.

Ответ 4

Я использовал иначе, чем HYRY:

  • выполните регулярное слияние с внешним соединением (how = 'outer');
  • сортировать по дате;
  • используйте fillna (method = 'pad'), чтобы заполнить только нужные столбцы и "pad", если вы хотите взять предыдущую заполненную строку;
  • отбросить все строки, которые вам не нужны из внешнего соединения.

Все это можно записать несколькими строками:

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]