Существует ли функциональность pandas для ежедневного извлечения определенных меток времени из столбца даты и времени?

#python #pandas #finance

Вопрос:

У меня есть набор данных с информацией о тикерах с отметками времени, охватывающими более месяца, но мне нужно захватить только время в 4:00 вечера. Ближайший к этому тик-16:00:03, который я сейчас использую. Я жестко закодировал долины за август, вручную введя даты, но хотел бы изменить это, чтобы я мог указать, какой месяц использовать вместо ввода каждый день или установки даты начала и окончания.

 df = df.loc[((df["timestamp"] == "2021-08-02 16:00:03")) | 
           ((df["timestamp"] == "2021-08-03 16:00:03")) |
           ((df["timestamp"] == "2021-08-04 16:00:03")) |
           ((df["timestamp"] == "2021-08-05 16:00:03")) |
           ((df["timestamp"] == "2021-08-06 16:00:03")) ]

 
     timestamp           bidprice    askprice
0   2021-08-02 14:59:03 99.937500   99.949219
1   2021-08-02 15:00:03 99.941406   99.945312
2   2021-08-02 15:01:03 99.941406   99.945312
3   2021-08-02 15:02:03 99.941406   99.945312
4   2021-08-02 15:03:03 99.941406   99.945312
...
        timestamp           bidprice    askprice
468109  2021-09-01 22:55:02 110.500000  110.546875
468110  2021-09-01 22:56:02 110.500000  110.546875
468111  2021-09-01 22:57:02 110.500000  110.546875
468112  2021-09-01 22:58:02 110.484375  110.531250
468113  2021-09-01 22:59:02 110.484375  110.531250
 

Ответ №1:

Используйте asof слияние с фреймом данных, представляющим собой одну серию с ежедневным временем в 16:00:00. Вы можете указать направление 'nearest' 'forward' или 'backward' получить логику соответствия, которую вы хотели бы.

Примеры Данных

 import numpy as np
import pandas as pd

N = 30000
np.random.seed(123)
df1 = pd.DataFrame({'timestamp': (pd.date_range('2021-08-01', freq='29s', periods=N)
                                    pd.to_timedelta(np.random.normal(0,1,N), unit='ms')),
                    'value': range(N)})
 

Код

 #Daily 16:00:00 DataFrame
start_date = '2021-08-01 16:00:00'
end_date = '2021-08-11 16:00:00'
dfbase = pd.DataFrame({'date': pd.date_range(start_date, end_date, freq='D')})

result = pd.merge_asof(dfbase, df1.sort_values('timestamp'), 
                       left_on='date', right_on='timestamp',
                       direction='nearest', allow_exact_matches=True)
 

 print(result)

                  date                     timestamp  value
0  2021-08-01 16:00:00 2021-08-01 15:59:53.999784590   1986
1  2021-08-02 16:00:00 2021-08-02 16:00:14.000160424   4966
2  2021-08-03 16:00:00 2021-08-03 16:00:05.000322262   7945
3  2021-08-04 16:00:00 2021-08-04 15:59:55.998303052  10924
4  2021-08-05 16:00:00 2021-08-05 15:59:46.998877694  13903
5  2021-08-06 16:00:00 2021-08-06 16:00:06.998954204  16883
6  2021-08-07 16:00:00 2021-08-07 15:59:58.000602203  19862
7  2021-08-08 16:00:00 2021-08-08 15:59:49.001400290  22841
8  2021-08-09 16:00:00 2021-08-09 16:00:08.998636467  25821
9  2021-08-10 16:00:00 2021-08-10 15:59:59.998385577  28800
10 2021-08-11 16:00:00 2021-08-11 01:39:31.001659917  29999
 

Другой вариант, который даст вам аналогичный результат, как указано выше, но с меньшим количеством информации, можно использовать DataFrame.asof после установки индекса. Вы можете указать серию ежедневных дат.

 df1 = df1.set_index('timestamp')
df1.asof(dfbase.date)

                       value
date                        
2021-08-01 16:00:00   1986.0
2021-08-02 16:00:00   4965.0
2021-08-03 16:00:00   7944.0
2021-08-04 16:00:00  10924.0
2021-08-05 16:00:00  13903.0
2021-08-06 16:00:00  16882.0
2021-08-07 16:00:00  19862.0
2021-08-08 16:00:00  22841.0
2021-08-09 16:00:00  25820.0
2021-08-10 16:00:00  28800.0
2021-08-11 16:00:00  29999.0
 

Так же результат (некоторые строки, потому что это приводит 'backward' направлении на матч), но не дает никакой информации о точных временных меток, которая была согласована, а также не поддерживает настройки tolerance , чтобы исключить неудачные матчи (возможно, как последний ряд, который по-прежнему самый близкий, но плохой матч)

Ответ №2:

Во-первых, вы хотите преобразовать строки даты и времени в метки времени

 df['timestamp'] = pd.to_datetime(df['timestamp'])
 

Затем изолировать

 df = df.loc[df['timestamp'] == datetime.time(hour=16, minute=3)]
 

Извините за мой непроверенный код, но это, по крайней мере, должно вывести вас на правильный путь.