Pandas Dataframe - отбрасывание определенных часов дня из 20 лет исторических данных - PullRequest
8 голосов
/ 28 марта 2020

У меня есть данные по фондовому рынку для одной ценной бумаги за 20 лет. Данные в настоящее время находятся в Pandas DataFrame, в следующем формате:

enter image description here

Проблема в том, что я не хочу никаких "в нерабочее время" торговые данные в моем DataFrame. Данный рынок открыт с 9:30 до 16:00 (с 09:30 до 16:00 в каждый торговый день). Я хотел бы отбросить все строки данных, которые не в течение этого периода времени.

Мой инстинкт состоит в том, чтобы использовать маску Pandas, которую я знаю, как сделать, если бы я хотел определенные часы в один день:

mask = (df['date'] > '2015-07-06 09:30:0') & (df['date'] <= '2015-07-06 16:00:0')
sub = df.loc[mask]

Однако я понятия не имею, как используйте один на возобновляемой основе, чтобы удалить данные за определенное время дня в течение 20-летнего периода.

Ответы [ 3 ]

8 голосов
/ 28 марта 2020

Проблема здесь в том, как вы импортируете данные. Нет никакого индикатора, является ли 04:00 утра или вечера? но исходя из ваших комментариев мы должны предположить, что это PM. Однако входные данные показывают его как AM.

Чтобы решить эту проблему, нам нужно включить два условия с предложением OR.

  1. 9: 30-11: 59
  2. 0: 00-4: 00

Ввод:

df = pd.DataFrame({'date':   {880551: '2015-07-06 04:00:00', 880552: '2015-07-06 04:02:00',880553: '2015-07-06 04:03:00', 880554: '2015-07-06 04:04:00', 880555: '2015-07-06 04:05:00'},
                   'open':   {880551: 125.00, 880552: 125.36,880553: 125.34, 880554: 125.08, 880555: 125.12},
                   'high':   {880551: 125.00, 880552: 125.36,880553: 125.34, 880554: 125.11, 880555: 125.12},
                   'low':    {880551: 125.00, 880552: 125.32,880553: 125.21, 880554: 125.05, 880555: 125.12},
                   'close':  {880551: 125.00, 880552: 125.32,880553: 125.21, 880554: 125.05, 880555: 125.12},
                   'volume': {880551: 141, 880552: 200,880553: 750, 880554: 17451, 880555: 1000},
                   },
                   )


df.head()

    date    open    high    low close   volume
880551  2015-07-06 04:00:00 125.00  125.00  125.00  125.00  141
880552  2015-07-06 04:02:00 125.36  125.36  125.32  125.32  200
880553  2015-07-06 04:03:00 125.34  125.34  125.21  125.21  750
880554  2015-07-06 04:04:00 125.08  125.11  125.05  125.05  17451
880555  2015-07-06 04:05:00 125.12  125.12  125.12  125.12  1000

from datetime import time

start_first = time(9, 30)
end_first = time(11, 59)
start_second = time(0, 00)
end_second = time(4,00)
df['date'] = pd.to_datetime(df['date'])
df= df[(df['date'].dt.time.between(start_first, end_first)) | (df['date'].dt.time.between(start_second, end_second))]
df
date    open    high    low close   volume
880551  2015-07-06 04:00:00 125.0   125.0   125.0   125.0   141

выше Это не очень хорошая практика, и я настоятельно не рекомендую использовать такие неоднозначные данные. Долгое время решение состоит в том, чтобы правильно заполнить данные am / pm.

Мы можем достичь этого двумя способами в случае правильного формата данных:

1) используя datetime

from datetime import time

start = time(9, 30)
end = time(16)
df['date'] = pd.to_datetime(df['date'])
df= df[df['date'].dt.time.between(start, end)]

2) использование между временем, которое работает только с указателем даты и времени

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

df = (df.set_index('date')
          .between_time('09:30', '16:00')
          .reset_index())

Если вы все еще сталкиваетесь с ошибкой, отредактируйте свой вопрос с построчным подходом и точной ошибкой.

3 голосов
/ 02 апреля 2020

Я думаю, что ответ уже есть в комментариях (@ Parfait's .between_time ), но он потерян в вопросах отладки. Похоже, что ваш столбец df['date'] еще не относится к типу Datetime.

Этого должно быть достаточно, чтобы это исправить и получить требуемый результат:

df['date'] = pd.to_datetime(df['date'])
df = df.set_index('date')
df = df.between_time('9:30', '16:00')
0 голосов
/ 05 апреля 2020

Этот пример кода объединяет ответы, предоставленные Bhave sh Ghodasara, Parfait и jorijnsmit в один полный, прокомментированный пример:

import pandas as pd

# example dataframe containing 6 records: 2 days of 3 records each in which all cases are covered:
# each day has one record before trading hours, one record during trading hours and one recrod after trading hours
df = pd.DataFrame({'date':   {0: '2015-07-06 08:00:00', 1: '2015-07-06 13:00:00', 2: '2015-07-06 18:00:00', 
                              3: '2015-07-07 08:00:00', 4: '2015-07-07 13:00:00', 5: '2015-07-07 18:00:00'},
                   'open':   {0: 125.00, 1: 125.36, 2: 125.34, 3: 125.08, 4: 125.12, 5: 125.37},
                   'high':   {0: 125.00, 1: 125.36, 2: 125.34, 3: 125.08, 4: 125.12, 5: 125.37},
                   'low':    {0: 125.00, 1: 125.36, 2: 125.34, 3: 125.08, 4: 125.12, 5: 125.37},
                   'close':  {0: 125.00, 1: 125.36, 2: 125.34, 3: 125.08, 4: 125.12, 5: 125.37},
                   'volume': {0: 141, 1: 200, 2: 750, 3: 17451, 4: 1000, 5: 38234},
                   },
                   )

# inspect the example data set
df.head(6)

# first, ensure that the 'date' column is of the correct data type: MAKE IT SO!
df['date'] = pd.to_datetime(df['date'])

# inspect the data types: date column should be of type 'datetime64[ns]'
print(df.dtypes)

# set the index of the dataframe to the datetime-type column 'data'
df = df.set_index('date')

# inspect the index: it should be a DatetimeIndex of dtype 'datetime64[ns]'
print(df.index)

# filter the data set
df_filtered = df.between_time('9:30', '16:00')

# inspect the filtered data set: Voilà! No more outside trading hours records.
df_filtered.head()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...