给定时间戳,匹配与它最接近的旧值(merge_asof 等两个方法)

merge_asof

除了匹配最近的键而不是相等的键之外,其他的都类似于有序的left-join 。 对于左侧DataFrame中的每一行,我们选择右侧DataFrame中on键对应的值小于left的键对应的值的最后一行。 两个DataFrame必须按键排序。

trades = pd.DataFrame({
     'time': pd.to_datetime(['20160525 13:30:00.023',
                             '20160525 13:30:00.038',
                             '20160525 13:30:00.048',
                             '20160525 13:30:00.048',
                             '20160525 13:30:00.048']),
     'ticker': ['MSFT', 'MSFT',
                'GOOG', 'GOOG', 'AAPL'],
     'price': [51.95, 51.95,
                 720.77, 720.92, 98.00],
     'quantity': [75, 155,
                    100, 100, 100]},
      columns=['time', 'ticker', 'price', 'quantity'])
  

quotes = pd.DataFrame({
      'time': pd.to_datetime(['20160525 13:30:00.023',
                              '20160525 13:30:00.023',
                              '20160525 13:30:00.030',
                              '20160525 13:30:00.041',
                              '20160525 13:30:00.048',
                              '20160525 13:30:00.049',
                              '20160525 13:30:00.072',
                              '20160525 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]},
     columns=['time', 'ticker', 'bid', 'ask'])


trades
Out[4]: 
                     time ticker   price  quantity
0 2016-05-25 13:30:00.023   MSFT   51.95        75
1 2016-05-25 13:30:00.038   MSFT   51.95       155
2 2016-05-25 13:30:00.048   GOOG  720.77       100
3 2016-05-25 13:30:00.048   GOOG  720.92       100
4 2016-05-25 13:30:00.048   AAPL   98.00       100

quotes
Out[5]: 
                     time ticker     bid     ask
0 2016-05-25 13:30:00.023   GOOG  720.50  720.93
1 2016-05-25 13:30:00.023   MSFT   51.95   51.96
2 2016-05-25 13:30:00.030   MSFT   51.97   51.98
3 2016-05-25 13:30:00.041   MSFT   51.99   52.00
4 2016-05-25 13:30:00.048   GOOG  720.50  720.93
5 2016-05-25 13:30:00.049   AAPL   97.99   98.01
6 2016-05-25 13:30:00.072   GOOG  720.50  720.88
7 2016-05-25 13:30:00.075   MSFT   52.01   52.03

下面Oder的顺序是按照ticker排序,连接键是time:

pd.merge_asof(trades, quotes,
             on='time',
             by='ticker')
Out[6]: 
                     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

可以看出相当于left_join,只根据left的key进行merge。值得注意的是,right对应的值的time最大不能超过left的time,比如left中 2016-05-25 13:30:00.038 MSFT,那么拼接的right对应的时间最大是 2016-05-25 13:30:00.030 MSFT 51.97 51.98。APPL在right中就没有对应的值。

tolerance:添加容忍的时间差;例如我们仅在报价时间和交易时间之间的2ms内,意味着交易的时间减去10ms再进行比较

pd.merge_asof(trades, quotes,on='time',by='ticker',tolerance=pd.Timedelta('2ms'))
Out[7]: 
                     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

我们仅在报价时间和交易时间之间的10ms内,我们按时排除完全匹配。 请注意,虽然我们排除了(报价quote)完全匹配,但先前的quote会传播到该时间点。

pd.merge_asof(trades, quotes,
                  on='time',
                  by='ticker',
                  tolerance=pd.Timedelta('10ms'),
                  allow_exact_matches=False)
Out[8]: 
                     time ticker   price  quantity    bid    ask
0 2016-05-25 13:30:00.023   MSFT   51.95        75    NaN    NaN
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    NaN    NaN
3 2016-05-25 13:30:00.048   GOOG  720.92       100    NaN    NaN
4 2016-05-25 13:30:00.048   AAPL   98.00       100    NaN    NaN
函数实现

找到给定时间戳之前最接近的值:

def get_nearest_past(data, timestamp):
    index = data.index.get_loc(timestamp,"ffill")
    return data.iloc[index]

如果想得到全局最接近给定时间戳的值,则是:

def get_nearest(data, timestamp):
    index = data.index.get_loc(timestamp,"nearest")
    return data.iloc[index]

备注:这两个函数没有验证过,留档备查。

参考资料:
[1] https://blog.csdn.net/brucewong0516/article/details/82935136
[2] https://www.cnpython.com/qa/52860

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值