作用
pd.merge_asof() ,是用来进行时序数据合并的。这个函数比较难也不常用,我们来简单做下学习笔记。
右边的数据,会找左边最接近的日期去合并。backward往上找,forward往下找,nearest最近
它会基于关键字段和时间阈值,将行连接在一起。如果:
- 右侧 DataFrame 的时间,晚于左侧 DataFrame 的时间
- 差值小于等于阈值
则连接两行
阈值
通过 tolerance 参数传递阈值。
该参数指定了两个时间序列中,所允许的最大时间差。
如果不指定 tolerance 参数,则默认为 pd.Timedelta(seconds=1)。
与pd.merge的关系
pd.merge_asof() 函数适用于时间序列数据;而 pd.merge() 适用于普通的关系型数据
示例1
import pandas as pd
quotes = pd.DataFrame(
{
"time": [
pd.Timestamp("2016-05-25 13:30:00.023"),
pd.Timestamp("2016-05-25 13:30:00.023"),
pd.Timestamp("2016-05-25 13:30:00.030"),
pd.Timestamp("2016-05-25 13:30:00.041"),
pd.Timestamp("2016-05-25 13:30:00.048"),
pd.Timestamp("2016-05-25 13:30:00.049"),
pd.Timestamp("2016-05-25 13:30:00.072"),
pd.Timestamp("2016-05-25 13:30:00.075")
],
"ticker": [
"GOOG",
"MSFT",
"MSFT",
"MSFT",
"GOOG",
"AAPL",
"GOOG",
"MSFT"
],
"bid": [720.50, 51.95, 51.97, 51.99, 720.50, 97.99, 720.50, 52.01],
"ask": [720.93, 51.96, 51.98, 52.00, 720.93, 98.01, 720.88, 52.03]
}
)
trades = pd.DataFrame(
{
"time": [
pd.Timestamp("2016-05-25 13:30:00.023"),
pd.Timestamp("2016-05-25 13:30:00.038"),
pd.Timestamp("2016-05-25 13:30:00.048"),
pd.Timestamp("2016-05-25 13:30:00.048"),
pd.Timestamp("2016-05-25 13:30:00.048")
],
"ticker": ["MSFT", "MSFT", "GOOG", "GOOG", "AAPL"],
"price": [51.95, 51.95, 720.77, 720.92, 98.0],
"quantity": [75, 155, 100, 100, 100]
}
)
merged = pd.merge_asof(
trades,
quotes,
on="time",
by="ticker",
tolerance=pd.Timedelta("2ms")
)
print(merged)
结果
time ticker price quantity bid ask
0 2016-05-25 13:30:00.023 MSFT 51.95 75 51.95 51.96
1 2016-05-25 13:30:00.038 MSFT 51.95 155 NaN NaN
2 2016-05-25 13:30:00.048 GOOG 720.77 100 720.50 720.93
3 2016-05-25 13:30:00.048 GOOG 720.92 100 720.50 720.93
4 2016-05-25 13:30:00.048 AAPL 98.00 100 NaN NaN
可以看到,第二个MSFT无法合并进去。
这是因为,quotes的第三行数据time为2016-05-25 13:30:00.030,比trade的第2行数据的time2016-05-25 13:30:00.038相差8毫秒。将tolerance调大为8ms,就可以合并了。
merged = pd.merge_asof(
trades,
quotes,
on="time",
by="ticker",
tolerance=pd.Timedelta("8ms")
)
结果
time ticker price quantity bid ask
0 2016-05-25 13:30:00.023 MSFT 51.95 75 51.95 51.96
1 2016-05-25 13:30:00.038 MSFT 51.95 155 51.97 51.98
2 2016-05-25 13:30:00.048 GOOG 720.77 100 720.50 720.93
3 2016-05-25 13:30:00.048 GOOG 720.92 100 720.50 720.93
4 2016-05-25 13:30:00.048 AAPL 98.00 100 NaN NaN
当然,也可以调整direction为forward,可以改变对时间做差时候的方向。
示例2
import pandas as pd
left = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],
'left': ['L0', 'L1', 'L2', 'L3'],
'time': pd.to_datetime(['2021-01-01', '2021-01-02', '2021-01-05', '2021-01-06'])})
right = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],
'right': ['R0', 'R1', 'R2', 'R3'],
'time': pd.to_datetime(['2021-01-01', '2021-01-03', '2021-01-04', '2021-01-05'])})
merged = pd.merge_asof(left, right, by='key', on='time', tolerance=pd.Timedelta(days=1), direction='forward')
print(merged)
结果
key left time right
0 K0 L0 2021-01-01 R0
1 K1 L1 2021-01-02 R1
2 K2 L2 2021-01-05 NaN
3 K3 L3 2021-01-06 NaN
可以看到,forward是left比right早,才可以合并进去
将direction改为backward,结果为:
key left time right
0 K0 L0 2021-01-01 R0
1 K1 L1 2021-01-02 NaN
2 K2 L2 2021-01-05 R2
3 K3 L3 2021-01-06 R3
可以猜测,合并的时候,它应该是逐行进行的,满足条件就匹配
补充
这个函数,要求两个df的time列,必须是排过序的
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情