Dataframe do Pandas - Eliminando determinadas horas do dia de 20 anos de dados históricos


8

Tenho dados do mercado de ações para uma única segurança que remonta a 20 anos. Os dados estão atualmente em um DataFrame do Pandas, no seguinte formato:

insira a descrição da imagem aqui

O problema é que eu não quero nenhum dado comercial "fora do horário comercial" no meu DataFrame. O mercado em questão está aberto das 9:30 às 16:00 (09:30 às 16:00 em cada dia de negociação). Gostaria de eliminar todas as linhas de dados que não estão dentro desse período.

Meu instinto é usar uma máscara de pandas, que eu sei fazer se quisesse certas horas em um único dia:

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

No entanto, não tenho idéia de como usá-lo em uma base rotativa para remover os dados para determinadas horas do dia durante um período de 20 anos.


qual é o tipo de dados da coluna date. Você poderia executar este comando print(df['date'].map(type)) e postar sua saída na pergunta?
Andy L.

Respostas:


8

O problema aqui é como você está importando dados. Não há indicador se 04:00 é am ou pm? mas com base nos seus comentários, precisamos assumir que é PM. No entanto, a entrada está mostrando como AM.

Para resolver isso, precisamos incluir duas condições com a cláusula OR.

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

Entrada:

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

Acima não é uma boa prática, e eu desencorajo fortemente a usar esse tipo de dados ambíguos. A solução de longo prazo é preencher corretamente os dados com am / pm.

Podemos alcançá-lo de duas maneiras, no caso de formato de dados correto:

1) usando 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) usando entre o tempo, que funciona apenas com o índice de data e hora

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

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

Se você ainda enfrentar um erro, edite sua pergunta com abordagem linha a linha e erro exato.


Isso resulta no seguinte erroTypeError: Index must be DatetimeIndex
HMLDude

editei minha resposta, df ['date'] = pd.to_datetime (df ['date'])
Bhavesh Ghodasara 28/03

A partir desta publicação do SO , parece que o between_timequadro de dados é um índice de data e hora. OP pode tentar a nível trama de dados: day_df = df.set_index('date').between_time('9:30', '16:00').
Parfait

BhaveshGhodasara Tentei o que você sugeriu em suas edições mais recentes e o resultado é o mesmo TypeError: Index must be DatetimeIndex.
HMLDude 28/03

@Parfait Tentei sua sugestão bem e mais uma vez a mensagem de erro foi: TypeError: Index must be DatetimeIndex.
HMLDude 28/03

3

Acho que a resposta já está nos comentários (@ parfait's .between_time ), mas que se perdeu em problemas de depuração. Parece que sua df['date']coluna ainda não é do tipo Datetime.

Isso deve ser suficiente para corrigir isso e obter o resultado necessário:

df['date'] = pd.to_datetime(df['date'])
df = df.set_index('date')
df = df.between_time('9:30', '16:00')

0

Este código de exemplo consolida as respostas fornecidas por Bhavesh Ghodasara, Parfait e jorijnsmit em um exemplo completo e comentado:

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()
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.