KDB + как объединение для данных таймсеров в pandas?
kdb + имеет функцию aj, которая обычно используется для объединения таблиц по столбцам времени.
Вот пример, где у меня есть таблицы торговли и цитаты, и я получаю преобладающую цитату для каждой сделки.
q)5# t
time sym price size
-----------------------------
09:30:00.439 NVDA 13.42 60511
09:30:00.439 NVDA 13.42 60511
09:30:02.332 NVDA 13.42 100
09:30:02.332 NVDA 13.42 100
09:30:02.333 NVDA 13.41 100
q)5# q
time sym bid ask bsize asize
-----------------------------------------
09:30:00.026 NVDA 13.34 13.44 3 16
09:30:00.043 NVDA 13.34 13.44 3 17
09:30:00.121 NVDA 13.36 13.65 1 10
09:30:00.386 NVDA 13.36 13.52 21 1
09:30:00.440 NVDA 13.4 13.44 15 17
q)5# aj[`time; t; q]
time sym price size bid ask bsize asize
-----------------------------------------------------
09:30:00.439 NVDA 13.42 60511 13.36 13.52 21 1
09:30:00.439 NVDA 13.42 60511 13.36 13.52 21 1
09:30:02.332 NVDA 13.42 100 13.34 13.61 1 1
09:30:02.332 NVDA 13.42 100 13.34 13.61 1 1
09:30:02.333 NVDA 13.41 100 13.34 13.51 1 1
Как я могу выполнить ту же операцию с помощью pandas? Я работаю с торговлей и цитированием данных, где индекс равен datetime64.
In [55]: quotes.head()
Out[55]:
bid ask bsize asize
2012-09-06 09:30:00.026000 13.34 13.44 3 16
2012-09-06 09:30:00.043000 13.34 13.44 3 17
2012-09-06 09:30:00.121000 13.36 13.65 1 10
2012-09-06 09:30:00.386000 13.36 13.52 21 1
2012-09-06 09:30:00.440000 13.40 13.44 15 17
In [56]: trades.head()
Out[56]:
price size
2012-09-06 09:30:00.439000 13.42 60511
2012-09-06 09:30:00.439000 13.42 60511
2012-09-06 09:30:02.332000 13.42 100
2012-09-06 09:30:02.332000 13.42 100
2012-09-06 09:30:02.333000 13.41 100
Я вижу, что pandas имеет функцию asof, но это не определено в DataFrame, только на объекте Series. Я предполагаю, что можно пройти через каждую из Серии и выровнять их один за другим, но мне интересно, есть ли лучший способ?
Ответы
Ответ 1
Как вы упомянули в вопросе, цикл для каждого столбца должен работать на вас:
df1.apply(lambda x: x.asof(df2.index))
Мы могли бы создать более быструю NaN-наивную версию DataFrame.asof, чтобы сделать все столбцы одним выстрелом. Но сейчас я считаю, что это самый простой способ.
Ответ 2
Я написал недокопированную функцию ordered_merge
некоторое время назад:
In [27]: quotes
Out[27]:
time bid ask bsize asize
0 2012-09-06 09:30:00.026000 13.34 13.44 3 16
1 2012-09-06 09:30:00.043000 13.34 13.44 3 17
2 2012-09-06 09:30:00.121000 13.36 13.65 1 10
3 2012-09-06 09:30:00.386000 13.36 13.52 21 1
4 2012-09-06 09:30:00.440000 13.40 13.44 15 17
In [28]: trades
Out[28]:
time price size
0 2012-09-06 09:30:00.439000 13.42 60511
1 2012-09-06 09:30:00.439000 13.42 60511
2 2012-09-06 09:30:02.332000 13.42 100
3 2012-09-06 09:30:02.332000 13.42 100
4 2012-09-06 09:30:02.333000 13.41 100
In [29]: ordered_merge(quotes, trades)
Out[29]:
time bid ask bsize asize price size
0 2012-09-06 09:30:00.026000 13.34 13.44 3 16 NaN NaN
1 2012-09-06 09:30:00.043000 13.34 13.44 3 17 NaN NaN
2 2012-09-06 09:30:00.121000 13.36 13.65 1 10 NaN NaN
3 2012-09-06 09:30:00.386000 13.36 13.52 21 1 NaN NaN
4 2012-09-06 09:30:00.439000 NaN NaN NaN NaN 13.42 60511
5 2012-09-06 09:30:00.439000 NaN NaN NaN NaN 13.42 60511
6 2012-09-06 09:30:00.440000 13.40 13.44 15 17 NaN NaN
7 2012-09-06 09:30:02.332000 NaN NaN NaN NaN 13.42 100
8 2012-09-06 09:30:02.332000 NaN NaN NaN NaN 13.42 100
9 2012-09-06 09:30:02.333000 NaN NaN NaN NaN 13.41 100
In [32]: ordered_merge(quotes, trades, fill_method='ffill')
Out[32]:
time bid ask bsize asize price size
0 2012-09-06 09:30:00.026000 13.34 13.44 3 16 NaN NaN
1 2012-09-06 09:30:00.043000 13.34 13.44 3 17 NaN NaN
2 2012-09-06 09:30:00.121000 13.36 13.65 1 10 NaN NaN
3 2012-09-06 09:30:00.386000 13.36 13.52 21 1 NaN NaN
4 2012-09-06 09:30:00.439000 13.36 13.52 21 1 13.42 60511
5 2012-09-06 09:30:00.439000 13.36 13.52 21 1 13.42 60511
6 2012-09-06 09:30:00.440000 13.40 13.44 15 17 13.42 60511
7 2012-09-06 09:30:02.332000 13.40 13.44 15 17 13.42 100
8 2012-09-06 09:30:02.332000 13.40 13.44 15 17 13.42 100
9 2012-09-06 09:30:02.333000 13.40 13.44 15 17 13.41 100
Это может быть легко (ну, для кого-то, знакомого с кодом), расширенного как "левое соединение", имитирующее KDB. В этом случае я понимаю, что форвардное заполнение торговых данных не подходит; просто иллюстрируя функцию.
Ответ 3
pandas 0.19 ввел asof join:
pd.merge_asof(trades, quotes, on='time')
Семантика очень похожа на функциональность в q/kdb +.